带你梳理我的Axios封装(TS)
深入梳理Axios封装(TS版)
axios 封装思路
实现
新建Http.tsx文件,创建一个Http的类,添加get、post、patch、delete四个选项。
import axios, {AxiosInstance, AxiosRequestConfig} from 'axios';
type GetConfig = Omit<AxiosRequestConfig, 'params' | 'url' | 'method'>
type PostConfig = Omit<AxiosRequestConfig, 'url' | 'data' | 'method'>
type PatchConfig = Omit<AxiosRequestConfig, 'url' | 'data'>
type DeleteConfig = Omit<AxiosRequestConfig, 'params'>
export class Http {
instance: AxiosInstance;
constructor(baseURL: string) {
this.instance = axios.create({
baseURL
});
}
get<R = unknown>(url: string, query?: Record<string, JSONValue>, config?: GetConfig) {
return this.instance.request<R>({...config, url: url, params: query, method: 'get'});
}
post<R = unknown>(url: string, data?: Record<string, JSONValue>, config?: PostConfig) {
return this.instance.request<R>({...config, url, data, method: 'post'});
}
patch<R = unknown>(url: string, data?: Record<string, JSONValue>, config?: PatchConfig) {
return this.instance.request<R>({...config, url, data, method: 'patch'});
}
delete<R =unknown>(url: string, query?: Record<string, string>, config?: DeleteConfig) {
return this.instance.request<R>({...config, url: url, params: query, method: 'delete'});
}
}
export const http = new Http('/api/v1');
Axios拦截器
设置请求太频繁429
http.instance.interceptors.response.use(
(response) => {
return response
},
(error) => {
if (error.response) {
const axiosError = error as AxiosError
if (axiosError.response?.status === 429) {
alert('你太频繁了')
}
}
throw error
}
)
保存得到的JWT
JWT定义
- 原来的Session是给用户传随机数,需要和真实数据之间找对应关系,JWT是直接把数据加密传给用户,用户解密得到真实数据,就不需要存对应内容,拿到的内容就是内容本身,只是改不了,必须要解密才能得到
- JWT由三部分组成:header头、payload身体、signature签名(密文)
- header:头部有两部分组成,头需要标记用的加密算法是什么,字段叫alg,还可以写类型:typ, 可以是请求或其他类型
- payload:把一个JSON写到Body里:UID等内容
- signature:S等于加密方式:第一部分加密等于私钥,第二部分是base64的header,第三部分是base64的body
S= 加密 (私钥, base64(header), base64(body))
,加私钥是因为加密需要用到,第二部分的header是为了让加密算法不固定,header主要用来选不同的机密算法,第三部分的body才是前文所说的UID
JWT的用法
- 先看看Session怎么做登录:前端发送post请求,得到Cookie,再get用户信息,服务器验证Cookie,由于浏览器会自动把Cookie加到请求里,所以这里前端不需要做操作就能得到相应的用户信息的JSON
- JWT怎么操作,用户登录前端发送请求:post/JWT,然后服务器返回JWT内容,第一部分私密我们不关心,第二部分是UID比较关心,第三部分是密文,也不关心,前端不需要把UID读出来,因为前端能读那么黑客也能读。
-
-
- JWT不是存到Cookie里的,需要前端手动存到localStorage里面
-
- 配置axios,让库所有请求的header都带上JWT,一般带在Auth开头的字段
-
- 发请求 Get/user
Toast加载中
设置_autoLoading提示
http.instance.interceptors.request.use((config) => { const jwt = localStorage.getItem('jwt') if (jwt) { config.headers!.Authorization = `Bearer ${jwt}` } if (config._autoLoading === true) { Toast.loading({ message: '加载中...', forbidClick: true, duration: 0 }) } return config })
使用示例
登录拿到jwt
const response = await http.post<{ jwt: string }>('/session', formData, {_autoLoading: true}) .catch(onError) localStorage.setItem('jwt', response.data.jwt) //forData onError 根据情况自定义
拿到JWT使用
await http.post<Resource<Item>>('/items', formData, {_autoLoading: true }).catch(onError)
完整封装代码
import axios, {AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse} from 'axios'; import {Toast} from 'vant'; type GetConfig = Omit<AxiosRequestConfig, 'params' | 'url' | 'method'> type PostConfig = Omit<AxiosRequestConfig, 'url' | 'data' | 'method'> type PatchConfig = Omit<AxiosRequestConfig, 'url' | 'data'> type DeleteConfig = Omit<AxiosRequestConfig, 'params'> export class Http { instance: AxiosInstance; constructor(baseURL: string) { this.instance = axios.create({ baseURL }); } get<R = unknown>(url: string, query?: Record<string, JSONValue>, config?: GetConfig) { return this.instance.request<R>({...config, url: url, params: query, method: 'get'}); } post<R = unknown>(url: string, data?: Record<string, JSONValue>, config?: PostConfig) { return this.instance.request<R>({...config, url, data, method: 'post'}); } patch<R = unknown>(url: string, data?: Record<string, JSONValue>, config?: PatchConfig) { return this.instance.request<R>({...config, url, data, method: 'patch'}); } delete<R = unknown>(url: string, query?: Record<string, string>, config?: DeleteConfig) { return this.instance.request<R>({...config, url: url, params: query, method: 'delete'}); } } export const http = new Http('api/v1'); http.instance.interceptors.request.use((config) => { const jwt = localStorage.getItem('jwt'); if (jwt) { config.headers!.Authorization = `Bearer ${jwt}`; } if (config._autoLoading === true) { Toast.loading({ message: '加载中...', forbidClick: true, duration: 0 }); } return config; }); http.instance.interceptors.response.use( (response) => { if (response.config._autoLoading === true) { Toast.clear(); } return response; }, (error: AxiosError) => { if (error.response?.config._autoLoading === true) { Toast.clear(); } throw error; } ); http.instance.interceptors.response.use( (response) => { return response; }, (error) => { if (error.response) { const axiosError = error as AxiosError; if (axiosError.response?.status === 429) { alert('你太频繁了'); } } throw error; } );
-
转载自:https://juejin.cn/post/7223558793845653541