真沒必要再對(duì) axios 進(jìn)行過度的封裝
很多同學(xué)喜歡對(duì)axios再進(jìn)行二次的封裝,但真的有必要嗎?
前幾天在某網(wǎng)站上看到一篇文章,說是用 ts 對(duì) axios 進(jìn)行了下封裝,從點(diǎn)贊量、評(píng)論量和訪問量上來看,有很多人都看過這篇文章了。

我之前也看過 axios 的源碼,也基于 axios 進(jìn)行過擴(kuò)展和二次封裝。對(duì) axios 的內(nèi)部原理和使用方式不可謂不熟悉。
雖然很多人在評(píng)論里說,收益匪淺啊,寫的真棒啊等等,但我通讀完整篇文章,得到的結(jié)論是:完全沒必要。
1. 完全沒必要
有的開發(fā)者喜歡基于 axios 再在外層封裝一層,但這種方式實(shí)現(xiàn)的成本太高。
無論是實(shí)現(xiàn)跟 axios 一樣的功能,還是外層進(jìn)行簡化,然后再按照 axios 的方式傳給 axios,都增加了很多開發(fā)的成本。如:
const?myAxios?=?async?(config)?=>?{
??/**
???*?中間各種封裝,然后最后再使用axios發(fā)起請求1
???*?*/
??try?{
????const?{?status,?data?}?=?await?axios(config);
????if?(status?>=?200?&&?status?<=?304)?{
??????return?data;
????}
??}?catch?(err)?{
????console.error(err);
??}
??return?null;
};
如有的開發(fā)者封裝時(shí),喜歡把 GET 請求方式的 params 字段和 POST 請求方式的 data 字段合并成一個(gè),覺得可以減少使用者對(duì)字段記憶的成本。然后組件內(nèi)部,再根據(jù)請求方式,決定傳給 axios 的 params 字段還是 data 字段?;蛘哂械钠帘蔚魧?duì)請求的配置,有的屏蔽掉 axios 對(duì)外返回的字段。
就像上面的簡要封裝,連攔截器、取消請求等功能都給屏蔽掉了。但是,又想用,怎么辦?那就靠著自己半吊子的知識(shí),自己再封裝一個(gè),然后再跟 axios 進(jìn)行對(duì)接,累不累啊。
有的人說他的要求更復(fù)雜,不二次額外封裝一層,都沒法用,比如:
一個(gè) url 同時(shí)只有發(fā)起一個(gè)請求; 有重試的機(jī)制,當(dāng)不滿足要求時(shí),最多可以重試 3 次; 統(tǒng)一的 loading 機(jī)制; 配置復(fù)雜,不同的 URL 有著不同的配置;
其實(shí),上面的這幾條需求,通過 axios 的攔截器就可以實(shí)現(xiàn)了,外面不用再封裝一層。
axios 庫本身就已經(jīng)提供了多種的擴(kuò)展方式,為什么不直接用呢?

1.1 方便擴(kuò)展的適配器
axios 可以自定義請求適配器 adapter。
很多同學(xué)說 fetch 已經(jīng)成為標(biāo)準(zhǔn)了,為什么 axios 內(nèi)部還不支持。其實(shí)相比 XMLHttpRequest ,fetch 還是多少有點(diǎn)欠缺的,如取消請求的 AbortController 在 IE 瀏覽器中并沒有實(shí)現(xiàn),同時(shí)也不支持上傳進(jìn)度和下載進(jìn)度。
因此,在 fetch 還沒有對(duì)齊 XMLHttpRequest 里的這些功能時(shí),內(nèi)部還很難使用 fetch 來實(shí)現(xiàn)。
若您真的想用 fetch 來進(jìn)行請求,完全可以按照文檔來擴(kuò)展您的適配器。如何實(shí)現(xiàn)自定義的適配器,您可以參考這篇文章 如何實(shí)現(xiàn) axios 的自定義適配器 adapter。
直接在適配器上進(jìn)行擴(kuò)展,而不是基于 axios 再在外層封裝一層,原因有幾個(gè):
不改變 axios 的使用方式,無論傳參的方式,還是數(shù)據(jù)返回的格式,都沒有任何的變化; 可以使用 axios 中提供的能力,如攔截器,轉(zhuǎn)換請求數(shù)據(jù)和響應(yīng)數(shù)據(jù)、支持防御 XSRF 等;
這種方式,對(duì)其他開發(fā)者也很友好,只要知道 axios 怎么用,就知道你封裝的這個(gè)怎么用。不用增加學(xué)習(xí)的成本。
1.2 各種形式的配置
axios 在配置上,可以進(jìn)行全局的配置和請求的單獨(dú)配置,同時(shí)還有請求攔截器和響應(yīng)攔截器,對(duì)某一類的請求進(jìn)行處理。
若所有請求的 url 的 baseURL 是相同的,那么就可以在全局配置中進(jìn)行配置;若某幾個(gè)接口的 baseUrl 跟別的不一樣,那么可以單獨(dú)對(duì)其進(jìn)行配置,或者在請求攔截器中,直接修改請求的 baseUrl。
axios.defaults.timeout?=?6000;?//?全局配置
/**
?*?攔截器中配置,若url中有`aaa`,則過期時(shí)間設(shè)置為4000ms
?**/
axios.interceptors.request.use(
??function?(config)?{
????if?(/aaa/.test(config.url))?{
??????config.timeout?=?4000;
????}
????return?config;
??},
??function?(error)?{
????return?Promise.reject(error);
??},
);
axios('https://www.xiabingbao.com',?{?timeout:?2000?});?//?單獨(dú)對(duì)某個(gè)請求進(jìn)行配置
這些不同的配置方式,我個(gè)人覺得已經(jīng)可以滿足絕大部分的需求了。
1.3 本身就支持 typescript
axios 源碼雖不是用 typescript 編寫的,但官方也是提供了 ts 定義的:index.d.ts。
那些上來就說用 typescript 封裝 axios 的,你確定不是在搞笑嗎?
而且,作為個(gè)人開發(fā)者,在開發(fā)和使用過程中,肯定會(huì)產(chǎn)生紕漏和 bug,比不過經(jīng)過多人驗(yàn)證過的倉庫。

2. 不是不能封裝
其實(shí)也不是不能封裝,畢竟 axios 作為一個(gè)通用的框架,它不可能適應(yīng)所有的項(xiàng)目和架構(gòu)。我不希望的是過度的封裝,既沒必要,又增加后來者的學(xué)習(xí)成本。
有的同學(xué)在 React/Vue 中封裝 axios,倒是可以有封裝的意義,比如在 React 中封裝一個(gè)請求的簡單 hook 等。
const?useAxios?=?(config)?=>?{
??const?[loading,?setLoading]?=?useState(false);
??const?[error,?setError]?=?useState(null);
??const?[result,?setResult]?=?useState(null);
??useEffect(()?=>?{
????setLoading(true);
????axios(config)
??????.then(setResult)
??????.catch(setError)
??????.finally(()?=>?{
????????setLoading(false);
??????});
??},?[]);
??return?{?loading,?error,?result?};
};
更具體的如何在 React 封裝一個(gè)請求的 hook,可以參考該鏈接:使用 react 的 hook 實(shí)現(xiàn)一個(gè) useRequest。
有的封裝,是為了減少項(xiàng)目整體的改造成本,和其他人學(xué)習(xí)新用法的成本。比如之前我也基于 axios,在外層封裝過一個(gè)請求庫。當(dāng)時(shí)為了跟之前的請求方式保持一致,就在外層額外封了一層。后來就出現(xiàn)當(dāng)需要擴(kuò)展功能時(shí),特別麻煩,還不如從一開始設(shè)計(jì)時(shí),就僅僅擴(kuò)展他的適配器,或者幾個(gè)簡單的配置就行。
在封裝的時(shí)候,首先我們要明白 axios 可以完成什么工作,他實(shí)現(xiàn)這些功能都有什么意義,為什么可以傳入這些字段,又為什么要返回了那么多字段(我明明只需要接口返回的 data)?
想明白這些問題,就知道我們要保留什么,如何進(jìn)行擴(kuò)展和封裝了。

3. 總結(jié)
自己實(shí)現(xiàn)出來的東西,大部分都比不上社區(qū)里經(jīng)過千錘百煉驗(yàn)證過的。而且在使用的過程中,還要考慮減少其他人的學(xué)習(xí)成本。
比如你就不想用 Vue,覺得 Vue 這個(gè)框架優(yōu)點(diǎn)大,然后選擇了一個(gè)叫mini-vue的框架來開發(fā)項(xiàng)目。就社區(qū)完善程度來說,這個(gè) mini 版肯定是比不上官方 Vue 的,后來者還得重新學(xué)習(xí) mini 版的語法,當(dāng)遇到問題時(shí),都不知道去問誰,畢竟這個(gè)問題,只有 mini 版里才會(huì)有,其他人用的少,解答的人也少。

你應(yīng)該知道的 7 個(gè) GitHub 功能


