ts封裝axios最佳實(shí)踐示例詳解
簡介
??看了一圈,大家對(duì) ts 封裝 axios 都各有見解。但都不是我滿意的吧,所以自己封裝了一個(gè)??。至于為什么敢叫最佳實(shí)踐,因?yàn)槲覞M意,就這么簡單粗暴????。
什么樣封裝才是最合理的
別再用 promise 包了,好嗎?
看了一下,很多人封裝 axios 的時(shí)候都用 promise 包裝了一層,甚至更有甚者用起了 try catch。為什么反對(duì)用 promise 包裝,因?yàn)?axios 返回的就是個(gè) promise ,脫褲子放屁,完全沒必要??♀?。至于 try catch 這個(gè)是用于捕獲未知錯(cuò)誤的,比如 JSON.parse 的時(shí)候,有些字符串就是無法轉(zhuǎn)換。記住一句話,濫用 try catch 和隨地大小便沒有區(qū)別。
一個(gè) request 方法梭哈,噗!我一口老血??
部分人直接就一個(gè) request 方法梭哈,所有參數(shù)與配置都寫在一起,看起來一點(diǎn)也不清晰,簡潔。請(qǐng)求有多種方式,get,post,put...,最合理的請(qǐng)求方式應(yīng)該是 instance[method](url, data, options)。對(duì)應(yīng) 請(qǐng)求地址、請(qǐng)求參數(shù)、請(qǐng)求配置項(xiàng),一目了然。
擴(kuò)展我需要的請(qǐng)求,不要再 ts-ignore 了??
如果 ts-ignore 用多了,就會(huì)產(chǎn)生依賴性。不排除情況緊急急著上線,或者 類型處理 復(fù)雜的,但是在有時(shí)間的時(shí)候,還是得優(yōu)化一下,作為程序員,追求優(yōu)雅,永不過時(shí)。
求你了!把攔截器拿出來吧??
封裝的時(shí)候我們都會(huì)封裝一個(gè)請(qǐng)求類,但對(duì)應(yīng)攔截器應(yīng)該解耦出來。因?yàn)槊總€(gè)域名的攔截器處理可能不一致,寫死的話封裝請(qǐng)求類的意義也就沒有了。
接口請(qǐng)求 then 里面又判斷后端返回碼判斷請(qǐng)求是否成功,太狗血了!??
????看到下面這種代碼,給我難受的啊。
api.post(url, data).then((res) => {
if (res.code === 1) {
// ...
} else {
// 全局消息提示
console.error(res.message)
}
})
既然是一個(gè) promise ,我們就應(yīng)該知道 promise 只有成功或者失敗。then 怎么會(huì)有成功錯(cuò)誤的處理呢?then 里面就是請(qǐng)求成功,沒有什么 if else,處理失敗去 catch 里面處理去。這么喜歡寫 if else,你是沒寫過單元測(cè)試是吧?
開整
OK,吐槽了這么多,這時(shí)候肯定就有人說了,光說誰不會(huì)啊,你整一個(gè)??!??
瞧你這話說的,一點(diǎn)活沒干,還讓你白嫖了。你咋這么能呢???
不過話說回來,我不要活在他人的評(píng)價(jià)里,我做這件事情不是因?yàn)槟愕闹S刺或者吹捧,而是我自己要做????。
接下來定一下要做的事情
- 封裝一個(gè)請(qǐng)求類
- 適當(dāng)擴(kuò)展
axios類型,為自定義配置打地基 - 支持自定義請(qǐng)求配置。如是否全局錯(cuò)誤提示
- 攔截器單獨(dú)拎出來,方便擴(kuò)展新的請(qǐng)求
開整之前先看看 axios 基本類型
// 這是 axios 請(qǐng)求類型定義,但是因?yàn)槲覀冃枰С肿远x配置,所以待會(huì)需要把它拓展一下
export interface AxiosRequestConfig<D = any> {
url?: string;
method?: Method | string;
baseURL?: string;
transformRequest?: AxiosRequestTransformer | AxiosRequestTransformer[];
transformResponse?: AxiosResponseTransformer | AxiosResponseTransformer[];
headers?: (RawAxiosRequestHeaders & MethodsHeaders) | AxiosHeaders;
params?: any;
paramsSerializer?: ParamsSerializerOptions;
data?: D;
timeout?: Milliseconds;
timeoutErrorMessage?: string;
withCredentials?: boolean;
// ...
}
// 這是 axios 請(qǐng)求返回類型定義,里面類型需要處理,所以這個(gè)我們也得處理一下。
export interface AxiosResponse<T = any, D = any> {
data: T;
status: number;
statusText: string;
headers: RawAxiosResponseHeaders | AxiosResponseHeaders;
// 這里的配置沒有支持拓展,所以待會(huì)也得處理一下
config: InternalAxiosRequestConfig<D>;
request?: any;
}
// 所以我們只需要改造 3 個(gè) axios 類型定義就行了
// 另外我們需要定義下自己的攔截器 和 請(qǐng)求結(jié)果封裝
Talk is cheap,show me the code.
代碼也不多,就也不多解釋了,基本注釋都加上了。下面是全部代碼。
import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
// 定義一個(gè)常見后端請(qǐng)求返回
type BaseApiResponse<T> = {
code: number
message: string
result: T
}
// 拓展 axios 請(qǐng)求配置,加入我們自己的配置
interface RequestOptions {
// 是否全局展示請(qǐng)求 錯(cuò)誤信息
globalErrorMessage?: boolean
// 是否全局展示請(qǐng)求 成功信息
globalSuccessMessage?: boolean
}
// 拓展自定義請(qǐng)求配置
interface ExpandAxiosRequestConfig<D = any> extends AxiosRequestConfig<D> {
interceptorHooks?: InterceptorHooks
requestOptions?: RequestOptions
}
// 拓展 axios 請(qǐng)求配置
interface ExpandInternalAxiosRequestConfig<D = any> extends InternalAxiosRequestConfig<D> {
interceptorHooks?: InterceptorHooks
requestOptions?: RequestOptions
}
// 拓展 axios 返回配置
interface ExpandAxiosResponse<T = any, D = any> extends AxiosResponse<T, D> {
config: ExpandInternalAxiosRequestConfig<D>
}
export interface InterceptorHooks {
requestInterceptor?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig
requestInterceptorCatch?: (error: any) => any
responseInterceptor?: (response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>
responseInterceptorCatch?: (error: any) => any
}
// 導(dǎo)出Request類,可以用來自定義傳遞配置來創(chuàng)建實(shí)例
export default class Request {
// axios 實(shí)例
private _instance: AxiosInstance
// 默認(rèn)配置
private _defaultConfig: ExpandAxiosRequestConfig = {
baseURL: '/api',
timeout: 5000,
requestOptions: {
globalErrorMessage: true,
globalSuccessMessage: false
}
}
private _interceptorHooks?: InterceptorHooks
constructor(config: ExpandAxiosRequestConfig) {
// 使用axios.create創(chuàng)建axios實(shí)例
this._instance = axios.create(Object.assign(this._defaultConfig, config))
this._interceptorHooks = config.interceptorHooks
this.setupInterceptors()
}
// 通用攔截,在初始化時(shí)就進(jìn)行注冊(cè)和運(yùn)行,對(duì)基礎(chǔ)屬性進(jìn)行處理
private setupInterceptors() {
this._instance.interceptors.request.use(this._interceptorHooks?.requestInterceptor, this._interceptorHooks?.requestInterceptorCatch)
this._instance.interceptors.response.use(this._interceptorHooks?.responseInterceptor, this._interceptorHooks?.responseInterceptorCatch)
}
// 定義核心請(qǐng)求
public request(config: ExpandAxiosRequestConfig): Promise<AxiosResponse> {
// !??!?? 注意:axios 已經(jīng)將請(qǐng)求使用 promise 封裝過了
// 這里直接返回,不需要我們?cè)偈褂?promise 封裝一層
return this._instance.request(config)
}
public get<T = any>(url: string, config?: ExpandAxiosRequestConfig): Promise<AxiosResponse<BaseApiResponse<T>>> {
return this._instance.get(url, config)
}
public post<T = any>(url: string, data?: any, config?: ExpandAxiosRequestConfig): Promise<T> {
return this._instance.post(url, data, config)
}
public put<T = any>(url: string, data?: any, config?: ExpandAxiosRequestConfig): Promise<T> {
return this._instance.put(url, data, config)
}
public delete<T = any>(url: string, config?: ExpandAxiosRequestConfig): Promise<T> {
return this._instance.delete(url, config)
}
}
以及使用的 demo。這個(gè)保姆級(jí)服務(wù)滿意嗎?
// 請(qǐng)求攔截器
const transform: InterceptorHooks = {
requestInterceptor(config) {
// 請(qǐng)求頭部處理,如添加 token
const token = 'token-value'
if (token) {
config!.headers!.Authorization = token
}
return config
},
requestInterceptorCatch(err) {
// 請(qǐng)求錯(cuò)誤,這里可以用全局提示框進(jìn)行提示
return Promise.reject(err)
},
responseInterceptor(result) {
// 因?yàn)?axios 返回不支持?jǐn)U展自定義配置,需要自己斷言一下
const res = result as ExpandAxiosResponse
// 與后端約定的請(qǐng)求成功碼
const SUCCESS_CODE = 1
if (res.status !== 200) return Promise.reject(res)
if (res.data.code !== SUCCESS_CODE) {
if (res.config.requestOptions?.globalErrorMessage) {
// 這里全局提示錯(cuò)誤
console.error(res.data.message)
}
return Promise.reject(res.data)
}
if (res.config.requestOptions?.globalSuccessMessage) {
// 這里全局提示請(qǐng)求成功
console.log(res.data.message)
}
// 請(qǐng)求返回值,建議將 返回值 進(jìn)行解構(gòu)
return res.data.result
},
responseInterceptorCatch(err) {
// 這里用來處理 http 常見錯(cuò)誤,進(jìn)行全局提示
const mapErrorStatus = new Map([
[400, '請(qǐng)求方式錯(cuò)誤'],
[401, '請(qǐng)重新登錄'],
[403, '拒絕訪問'],
[404, '請(qǐng)求地址有誤'],
[500, '服務(wù)器出錯(cuò)']
])
const message = mapErrorStatus.get(err.response.status) || '請(qǐng)求出錯(cuò),請(qǐng)稍后再試'
// 此處全局報(bào)錯(cuò)
console.error(message)
return Promise.reject(err.response)
}
}
// 具體使用時(shí)先實(shí)例一個(gè)請(qǐng)求對(duì)象
const request = new Request({
baseURL: '/api',
timeout: 5000,
interceptorHooks: transform
})
// 定義請(qǐng)求返回
interface ResModel {
str: string
num: number
}
// 發(fā)起請(qǐng)求
request
.post<ResModel>(
'/abc',
{
a: 'aa',
b: 'bb'
},
{
requestOptions: {
globalErrorMessage: true
}
}
)
.then((res) => {
console.log('res: ', res)
console.log(res.str)
})
可以看到鼠標(biāo)浮上去就能看到定義了,完美!

最后源碼地址: github.com/coveychen95…
以上就是ts封裝axios最佳實(shí)踐示例詳解的詳細(xì)內(nèi)容,更多關(guān)于ts封裝axios的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript 就地編輯實(shí)現(xiàn)代碼
最近正在看《javascript設(shè)計(jì)模式》,其中有一個(gè)'就地編輯'的示例,用來表現(xiàn)不同的繼承方式,看完之后想自己憑理解寫一個(gè)類似的東西。2010-05-05
JavaScript實(shí)現(xiàn)酷炫的鼠標(biāo)拖尾特效
這篇文章主要為大家介紹了通過JavaScript實(shí)現(xiàn)的一個(gè)超級(jí)好看的鼠標(biāo)拖尾特效,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)JavaScript有一定的幫助,感興趣的可以學(xué)習(xí)一下2021-12-12
javascript獲取select值的方法完整實(shí)例
這篇文章主要介紹了javascript獲取select值的方法,結(jié)合完整實(shí)例形式分析了javascript動(dòng)態(tài)遍歷與操作頁面元素相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-06-06
javascript實(shí)現(xiàn)unicode與ASCII相互轉(zhuǎn)換的方法
這篇文章主要介紹了javascript實(shí)現(xiàn)unicode與ASCII相互轉(zhuǎn)換的方法,涉及JavaScript字符串的遍歷、正則匹配及編碼轉(zhuǎn)換相關(guān)技巧,需要的朋友可以參考下2015-12-12
JavaScript+H5實(shí)現(xiàn)微信搖一搖功能
這篇文章主要為大家詳細(xì)介紹了JavaScript+H5實(shí)現(xiàn)微信搖一搖功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05
非常不錯(cuò)的功能強(qiáng)大代碼簡單的管理菜單美化版
由于網(wǎng)盤不穩(wěn)定,很多時(shí)候文件提示找不到,幸好U盤里存了. 喜歡這3個(gè)風(fēng)格的朋友們別在PM我啦.....我把文件傳到我服務(wù)器上了..2008-07-07
javascript中的try catch異常捕獲機(jī)制用法分析
這篇文章主要介紹了javascript中的try catch異常捕獲機(jī)制,簡單分析了try catch異常捕獲機(jī)制的基本定義與使用方法,需要的朋友可以參考下2016-12-12
JavaScript原生數(shù)組函數(shù)實(shí)例匯總
這篇文章主要介紹了JavaScript原生數(shù)組函數(shù)實(shí)例匯總,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10

