別在重複封裝 Axios 和 Interceptors 了

語言: CN / TW / HK

鑑於我一開啟掘金就是一篇 xxx axios xxx 二次封裝,以及我工作好幾年的情況,有感而發。

真的不要在重複造輪子了,為什麼?聽我說道。

  1. axios 本身 Api 就足夠簡單易用,攔截器/介面卡足夠擴充套件任何功能。
  2. 擅自封裝還會使得原有 Axios 受到影響,增加開發成本和理解成本。
  3. 本身就已經支援 Typescript,你要加 TS 配置的話稍微有點知識就知道能覆蓋型別了。

那是不是不用封裝

不是,我也沒有說讓大家不要封裝,而是不要在重複封裝,過度封裝,這些重複工作在我看來就不應該太過於操心。

甚至寫 API 方法我認為都是很沒有必要的(懶是最佳生產力),我會利用 @hairy/api-generator 生成 api / types。

怎麼封裝才是最合適

  1. 保留原有庫(axios)設計
  2. 可拔插,沒有也不影響
  3. 簡化配置,可擴充套件
  4. 功能單一原則

舉幾個栗子,這裡以我自己的工具庫 @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 文章卻都是包一層的所謂通用方案(這就是所謂的流量密碼?),真的蠻令人感到深思的...

最後宣告:本人戰五渣、懶鬼一個,文采也不好,大家輕噴!