別在重複封裝 Axios 和 Interceptors 了
鑑於我一開啟掘金就是一篇 xxx axios xxx 二次封裝,以及我工作好幾年的情況,有感而發。
真的不要在重複造輪子了,為什麼?聽我說道。
- axios 本身 Api 就足夠簡單易用,攔截器/介面卡足夠擴充套件任何功能。
- 擅自封裝還會使得原有 Axios 受到影響,增加開發成本和理解成本。
- 本身就已經支援 Typescript,你要加 TS 配置的話稍微有點知識就知道能覆蓋型別了。
那是不是不用封裝
不是,我也沒有說讓大家不要封裝,而是不要在重複封裝,過度封裝,這些重複工作在我看來就不應該太過於操心。
甚至寫 API 方法我認為都是很沒有必要的(懶是最佳生產力),我會利用 @hairy/api-generator 生成 api / types。
怎麼封裝才是最合適
- 保留原有庫(axios)設計
- 可拔插,沒有也不影響
- 簡化配置,可擴充套件
- 功能單一原則
舉幾個栗子,這裡以我自己的工具庫 @hairy/axios-bearer 作為示範。
自動解構響應體(data assign response)
我相信大家都有遇到過的情況了把,怎麼避免 data.data
由於執行順序規則 axiosWithAssignResponse 應該最先被呼叫。
- 解構所有返回的 data
ts
import axios from 'axios'
import { axiosWithAssignResponse } from '@hairy/axios-bearer'
axiosWithAssignResponse(axios|instance, '*')
// 保證型別正確, 假設你的data是 { code: xxx, message: '...', data: xxx }
module 'axios' {
interface AxiosResponse {
code?: number
message?: string
}
}
請求
ts
const { data, code, message, config, ...other } = await axios<string>('xxx')
// data(string) / code(number)...
- 只解構 data
ts
// 假設你的data是 { data: xxx }
axiosWithAssignResponse(axios|instance, ['data'])
// 由於本身型別就自帶 data,不需要處理型別
請求
ts
const { data } = await axios<string>('xxx')
// typeof data === 'string' >> true
自定義響應錯誤(custom error)
ts
import axios from 'axios'
import { axiosWithCustomError } from '@hairy/axios-bearer'
// 請求響應的 code === 0 將響應攔截為錯誤
axiosWithCustomError(axios, () => {
return response.data.code === 0
})
請求
ts
try {
await axios('xxx')
} catch(error) {
console.log(error.response.data.code) // 0
}
請求時攜帶引數(extra params)
這個請求我就不展示了,相信大部分都能理解
```ts import axios from 'axios' import { axiosWithExtraParams } from '@hairy/axios-bearer' // 直接攜帶(header) axiosWithExtraParams(axios, { token: '111' }, 'headers') // 回撥攜帶(header) const getExtraParams = () => { return { token: '111' } } axiosWithExtraParams(axios, getExtraParams, 'headers')
// 攜帶在 params、data axiosWithExtraParams(axios, { foo: 'xxx' }, 'params') axiosWithExtraParams(axios, { foo: 'xxx' }, 'data') ```
請求時攜帶 loading 處理(loading helper)
這個要做還要考慮多個請求等待問題,所以封裝成一個處理函式是最為恰當的,避免在多個專案重複寫。
請求攜帶 loading 處理是一個很偷懶的做法,一般來說 UI 比較有追求或者要求質量的情況下是不會大面積採用的。
ts import axios from 'axios' import { axiosWithLoadingHelper } from '@hairy/axios' axiosWithLoadingHelper( axios, // custom show (config) => {}, // custom hide (config) => {} ) // use axios.get('xxx', { loading: true }) // global use axios.defaults['loading'] = true
以這種思路封裝一個失敗重複請求
這個例子只是描述這種思路,更建議大家使用這個庫 axios-retry
ts
const axiosWithErrorRetry = (axios) => {
axios.interceptors.response.use(() => ...)
}
總結
無論什麼功能,普遍都能以這種方式擴充套件,不侷限於我所列的這些功能,我列的這些例子只是供大家參考和思考(一種思路),能理解這個思維就行,你也可以直接用我的工具庫。
放眼望去,其實很多庫都包含這種設計,例如 Vue 的 .use、node 框架的中介軟體、plugins 系統這種拔插式的外掛擴充套件方法。
無論什麼時候,我們都應該要以某種方法來避免程式碼冗餘,而不是遇到什麼問題就 copy 程式碼。當然,我也不想說的太過,但我認為,假如(我說假如)你在這個行業拼搏好幾年了,還在琢磨這種細枝末節的東西,沒有點累積只會 copy 或者重複造之前寫過的功能,那麼你真的要好好思考一下。
說起來現在開源社群這麼發達,看到發的 axios 文章卻都是包一層的所謂通用方案(這就是所謂的流量密碼?),真的蠻令人感到深思的...
最後宣告:本人戰五渣、懶鬼一個,文采也不好,大家輕噴!