不要再被誤導了,封裝 Axios 只看這一篇文章就行了
前端瓶子君,關注公眾號
回復算法,加入前端編程面試算法每日一題群
看很多網(wǎng)上的人的封裝 Axios 教程,但或多或少都有不太合適的點,這里為大家推薦我的最佳實踐。
攔截器不要返回數(shù)據(jù),依然返回 AxiosResponse 對象
網(wǎng)上的文章都讓你用 攔截器 直接返回數(shù)據(jù),這種作法其實是非常不妥的,這樣會讓你后續(xù)的功能很難進行拓展。
不推薦的做法
import?Axios?from?'axios'
const?client?=?Axios.create({
??//?你的配置
})
client.interceptors.response.use(response?=>?{
??//?網(wǎng)上的做法都是讓你直接返回數(shù)據(jù)
??//?這導致后續(xù)的一些功能難以支持
??return?response.data
})
export?default?client
復制代碼
推薦的做法
推薦使用函數(shù)代替攔截器
import?Axios,?{?AxiosRequestConfig?}?from?'axios'
const?client?=?Axios.create({
??//?你的配置
})
export?async?function?request(url:?string,?config?:?AxiosRequestConfig)?{
??const?response?=?await?client.request({?url,?...config?})
??const?result?=?response.data
??//?你的業(yè)務判斷邏輯
??return?result
}
export?default?client
復制代碼
到這里可能有人會說太麻煩,請稍等,繼續(xù)往下看。
為你的請求添加拓展
很多時候,我們的開發(fā)流程是這樣的:
發(fā)送請求?=>?拿到數(shù)據(jù)?=>?渲染內(nèi)容
復制代碼
但可惜的是,這只是理想情況,在某些特殊情況下,你還是需要處理異?;蝾~外的支持,如:
當請求失敗,希望能夠自動重試3次以上再失敗 分頁數(shù)據(jù)中,當新的請求發(fā)出,自動中斷上一次的請求 第三方提供 jsonp 接口,而你又只能使用靜態(tài)頁時 (ps: Axios 不支持 jsonp) 更多
當發(fā)送以上場景時,你只能默默的寫代碼支持,但如果你不攔截 Axios 的響應,那就可以使用開源社區(qū)提供的方案。
支持請求重試
安裝 axios-retry[1],可以讓你的 Axios 支持自動重試的功能
import?Axios,?{?AxiosRequestConfig?}?from?'axios'
import?axiosRetry?from?'axios-retry'
const?client?=?Axios.create({
??//?你的配置
})
//?安裝?retry?插件
//?當請求失敗后,自動重新請求,只有3次失敗后才真正失敗
axiosRetry(client,?{?retries:?3?})
export?async?function?request(url:?string,?config?:?AxiosRequestConfig)?{
??const?response?=?await?client.request({?url,?...config?})
??const?result?=?response.data
??//?你的業(yè)務判斷邏輯
??return?result
}
//?只有3次失敗后才真正失敗
const?data?=?request('http://example.com/test')
復制代碼
PS: axios-retry 插件支持配置單個請求
支持 jsonp 請求
安裝 axios-jsonp[2],可以讓你的 Axios 支持 jsonp 的功能。
import?Axios,?{?AxiosRequestConfig?}?from?'axios'
import?jsonpAdapter?from?'axios-jsonp'
const?client?=?Axios.create({
??//?你的配置
})
export?async?function?request(url:?string,?config?:?AxiosRequestConfig)?{
??const?response?=?await?client.request({?url,?...config?})
??const?result?=?response.data
??//?你的業(yè)務判斷邏輯
??return?result
}
export?function?jsonp(url:?string,?config?:?AxiosRequestConfig)?{
??return?request(url,?{?...config,?adapter:?jsonpAdapter?})
}
//?你現(xiàn)在可以發(fā)送?jsonp?的請求了
const?data?=?jsonp('http://example.com/test-jsonp')
復制代碼
支持 URI 版本控制
有開發(fā) Web API 經(jīng)驗的人都會遇到一個問題,如果 API 出現(xiàn)重大變更的時候,如何保證舊版可用的情況下,發(fā)布新的 API?
這種情況在服務端開發(fā)場景中,其實并不罕見,尤其是對外公開的 API,如: 豆瓣 API (已失效)。
當前主流的支持 3 種類型的版本控制:
| 類型 | 描述 |
|---|---|
| URI Versioning | 版本將在請求的 URI 中傳遞(默認) |
| Header Versioning | 自定義請求標頭將指定版本 |
| Media Type Versioning | Accept 請求的標頭將指定版本 |
URI 版本控制 是指在請求的 URI 中傳遞的版本,例如 https://example.com/v1/route 和 https://example.com/v2/route。
import?Axios,?{?AxiosRequestConfig?}?from?'axios'
const?client?=?Axios.create({
??//?你的配置
})
client.interceptors.request.use(config?=>?{
??//?最簡單的方案
??config.url?=?config.url.replace('{version}',?'v1')
??return?config
})
//?GET?/api/v1/users
request('/api/{version}/users')
復制代碼
Header 和 Media Type 模式,可以參考如下文章來實現(xiàn)
實現(xiàn) Web API Versioning 功能[3] nest versioning[4]
保持請求唯一
在一個支持翻頁的后臺表格頁,一個用戶擊翻頁按鈕,請求發(fā)出等待響應,但用戶這時點擊搜索,需要重新獲取數(shù)據(jù),支持你的情況可能是:
翻頁請求先回,搜索數(shù)據(jù)再回,數(shù)據(jù)顯示正常 搜索數(shù)據(jù)先回,翻頁數(shù)據(jù)再回,數(shù)據(jù)顯示異常(通常在負載均衡的場景中出現(xiàn))
為此,你希望能夠自動取消上一次請求,于是你看了 Axios 的取消請求,但好多地方都需要用到,于是可以將這個功能封裝成獨立的函數(shù)。
import?Axios?from?'axios'
const?CancelToken?=?Axios.CancelToken
export?function?withCancelToken(fetcher)?{
??let?abort
??function?send(data,?config)?{
????cancel()?//?主動取消
????const?cancelToken?=?new?CancelToken(cancel?=>?(abort?=?cancel))
????return?fetcher(data,?{?...config,?cancelToken?})
??}
??function?cancel(message?=?'abort')?{
????if?(abort)?{
??????abort(message)
??????abort?=?null
????}
??}
??return?[send,?cancel]
}
復制代碼
使用
function?getUser(id:?string,?config?:?AxiosRequestConfig)?{
??return?request(`api/user/${id}`,?config)
}
//?包裝請求函數(shù)
const?[fetchUser,?abortRequest]?=?withCancelToken(getUser)
//?發(fā)送請求
//?如果上一次請求還沒回來,會被自動取消
fetchUser('1000')
//?通常不需要主動調(diào)用
//?但可以在組件銷毀的生命周期中調(diào)用
abortRequest()
復制代碼
這樣不需要自動取消的時候,直接使用原函數(shù)即可,也不會影響原函數(shù)的使用
后語
Axios 封裝其實還有很多事情可以做,比如 全局錯誤處理 (一樣不能影響正常請求) 等,封裝也不應該只是利用攔截器直接返回數(shù)據(jù)。
另外請求模塊應該保持獨立,推薦拓展 AxiosRequestConfig 或做成一個個獨立的函數(shù),提供給外部調(diào)用,方便做成一個獨立的 HTTP 模塊。
關于本文
作者:zhengxs2018
https://juejin.cn/post/7053471988752318472
