? ? ?在前端開發中,http請求層的封裝可以極大提升代碼的復用性和可維護性,本文將完整的用axios封裝接口請求,配置請求與響應攔截器,封裝統一的請求方法全過程。
? ?封裝的目的和思路
? ? ? ? 在項目直接用axios發送請求當然沒問題,但是如果不做封裝,每個請求都需要手動處理token,錯誤提示等邏輯,容易重復,缺乏統一的loading處理邏輯,不同組件可以用不一致的方式調用axios增加維護成本。業務錯誤,比如登錄失敗權限不足不集中處理用戶體驗差。
? ? ? ? 所以我們統一封裝是為了實現這些目標。
? ? ? ? 1.封裝Axios實例+設置baseURL和超時。
? ? ? ? 2.添加請求攔截器:自動加token顯示Loading
? ? ? ? 3.添加響應攔截器 統一處理錯誤隱藏loading
? ? ? ? 4 暴露統一的get/post等請求方法
? ? ? ? 5.支持類型推導(泛型)
? ? ? step1:安裝Axios
? ? ? ? npm install axios?
? ? ?step2:創建Axios實例并且封裝基礎配置
// api/request.ts
import axios, { AxiosError } from 'axios'
import { message } from 'antd'
import { showLoading, hideLoading } from './loading'const instance = axios.create({baseURL: '/api', // 接口統一前綴timeout: 8000, // 超時時間timeoutErrorMessage: '請求超時,請稍后再試',withCredentials: false, // 是否攜帶 Cookie
})
為什么要用 axios.create?
可以創建多個實例,分別管理不同的 baseURL(如主站與后臺接口)。
不影響全局 axios,互不干擾。
step3:請求攔截器
instance.interceptors.request.use((config) => {showLoading()const token = localStorage.getItem('token')if (token) {config.headers.Authorization = 'Token::' + token}return { ...config }},(error: AxiosError) => {return Promise.reject(error)}
)
?請求攔截器做了什么?
? ? ? ? 1.請求前顯示 loading(配合 Ant Design 的 Spin)
? ? ? ? 2.自動從 localStorage 中讀取 token,統一加入到請求頭中?
? ? ? ? 3.你也可以添加其他自定義 headers,例如用戶 ID、語言偏好等
step4:響應攔截器--統一 錯誤處理以及成功返回data
????????
instance.interceptors.response.use((response) => {hideLoading()const data = response.dataif (data.code === 500001) {// 登錄失效message.error(data.msg || '身份已過期,請重新登錄')localStorage.removeItem('token')return Promise.reject(data)} else if (data.code !== 0) {// 業務錯誤message.error(data.msg || '請求錯誤,請稍后重試')return Promise.reject(data)}return data.data // 請求成功,返回業務數據},(error: AxiosError) => {hideLoading()message.error(error.message || '服務器異常,請稍后重試')return Promise.reject(error)}
)
??
? ? ? ? 攔截器可能有人不理解概念。這里把概念放在這里。
????????axios.interceptors.request.use 是 Axios 提供的 API,用來設置請求發出前的統一處理邏輯。
它接收兩個回調函數,第一個是處理請求體 config 的,我們通常在這里加上 token、顯示 loading,處理完之后必須返回 config 否則請求會被中斷。
????????第二個是請求配置階段發生錯誤時的處理函數,比如攔截器中拋出異常,這個函數里我們一般把錯誤通過 Promise.reject 拋出去,供 .catch 捕獲使用。
????????Axios 的響應攔截器也接收兩個回調函數,第一個是響應成功時調用,它的參數是 response,從中我們可以提取 response.data,然后判斷自定義的 code 字段,來決定是 token 過期、業務出錯還是成功。如果 token 過期或失敗,會彈出錯誤提示,并通過 Promise.reject 拋出錯誤。
????????第二個回調函數是響應失敗(如網絡錯誤、404、500)時觸發的,我們可以統一顯示“服務器異常”等提示,也用 Promise.reject 拋出錯誤,供組件用 .catch() 捕獲。
? ? 后端返回的 data 結構通常如下:
{
"code": 0,
"msg": "成功",
"data": { "userInfo": { ... } }
}
? ? ? ? ?然后我們就可以明顯看到我們請求攔截器實際上就是config這個請求體在發送之前我們去加一些邏輯去處理我們的config請求體。比如頭部加上Authorization屬性值為token把我們的token加上去。還有第二個回調函數,就是把錯誤作為Promise實例的reject(error)扔出去,這樣我們組件可以用.catch捕捉。
? ? ? ? 響應攔截器同理,response就是我們的響應體。我們響應體在到組件接收之前我們對響應體做一些處理,比如我們不需要響應體,我們只是想要里面的data.data那么成功就返回data.data如果token過期了久調用message這是個組件然后.error顯示錯誤比如token過期了。總之只要有響應體一定會返回data給到我們的組件。如果響應攔截的時候就發現報錯了那么就reject扔出error組件.catch捕獲。
step5:封裝統一請求方法(泛型)
export default {get<T>(url: string, params?: object): Promise<T> {return instance.get(url, { params })},post<T>(url: string, params?: object): Promise<T> {return instance.post(url, params)},// 后續可添加 put、delete 等
}
?????
為什么要用泛型 <T>
?
調用接口時能獲得接口返回值的類型提示,增強類型安全
調用時直接寫
const res = await api.get<YourType>(...)
step6:如何使用封裝后的請求
// api/user.ts
import request from './request'export const getUserInfo = () => {return request.get<{ name: string; age: number }>('/user/info')
}
? ? ? ? 通過引入對象的形式直接調用里面的方法就可以了,然后聲明泛型也就是我們如果需要返回值的話聲明返回值的類型。然后后面是傳過去的url訪問的接口。實際上訪問的地址是baseUrl+我們傳過去的url。
? ? ? ? 總結
?????????
?????????
?
?
?
?
????????
?
?