目录
[1. AxiosInstance](#1. AxiosInstance)
[2. AxiosRequestConfig](#2. AxiosRequestConfig)
[3. AxiosResponse](#3. AxiosResponse)
[4. AxiosError](#4. AxiosError)
[1. 基础封装](#1. 基础封装)
[2. 高级封装](#2. 高级封装)
前言
为了实现统一的网络请求处理和管理,在日常开发中我们常常封装 axios,来实现统一配置、设置请求拦截器和响应拦截器、错误处理等。
TypeScript可以给项目提供类型检查和类型推导,axios请求回来的数据也会受其检查。本文将提供axios结合ts写法的封装步骤和代码。
一、axios中的常见类型
1. AxiosInstance
表示axios请求的配置选项,包括URL、方法、头部、参数等。
2. AxiosRequestConfig
表示一个axios实例的类型,可以用于创建自定义配置的axios实例。
3. AxiosResponse
表示axios响应的数据结构,包括状态码、响应头和响应数据。
4. AxiosError
表示axios请求发生错误时的错误对象,包括错误消息、请求配置和响应信息(如果有)。
注意:如果没有跟类型,ts也会自动推到成相应类型。可以不写,但不能错写。
二、axios封装步骤
1. 安装依赖
在项目根目录下,使用 npm 或 yarn 命令安装 axios 和 @types/axios(用于提供 axios 的类型定义文件)
TypeScript
pnpm install axios @types/axios
2. 创建封装文件
在项目中创建一个新的文件,例如 request.ts
,用于封装 axios。可以根据项目需求结构化地组织这些文件。文件名根据个人习惯来,大都取 axios 、request 、http等。
3. 导入 axios
在 request.ts
文件中导入 axios 模块。
4. 添加默认配置
根据需要,在请求方法中设置默认的请求头、超时时间、响应数据格式等配置项。
5. 定义返回的数据类型
根据后端返回的数据,设置统一的请求结果接口。
6. 添加拦截器
如果需要使用拦截器,可以在 api.ts 文件中定义请求拦截器和响应拦截器,并注册到 axios 中。
7. 封装请求方法
根据项目需求,定义请求方法,例如 GET、POST、PUT、DELETE 等。可以使用泛型来指定请求和响应的数据类型,增加类型安全性。
8. 导出方法/实例
在 request.ts
文件末尾,将封装的请求方法进行导出。
三、封装后的完整代码
1. 基础封装
使用对象字面量方式创建一个单例的axios实例。
TypeScript
// 导入axios和所需的类型
import axios, { AxiosInstance, AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
// 默认配置
const service: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE || '/' // 设置API的基本URL,默认为根路径
})
// 请求拦截器,对请求配置进行一些处理或设置
service.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
return config
},
(error: AxiosError) => {
return Promise.reject(error)
}
)
// 响应拦截器,对响应结果进行处理或判断
service.interceptors.response.use(
(response: AxiosResponse) => {
if (response.status === 200) {
return response.data
}
return Promise.reject() // 如果响应状态不是200,则返回一个拒绝的Promise
},
(error: AxiosError) => {
return Promise.reject(error)
}
)
export default service // 导出封装好的axios实例
// 定义结果接口Result
export interface Result<T = unknown> {
message: string
code: number
data: T
[key: string]: any // 其他任意属性
}
export const http = {
// 发送GET请求的方法,可指定数据类型T,并返回一个Promise对象,其值为Result<T>类型
get<T = any>(url: string, data?: object): Promise<Result<T>> {
return service.get<T, Result<T>>(url, data);
},
// 发送POST请求的方法,同样可指定数据类型T,并返回一个Promise对象
post<T = any>(url: string, data?: object): Promise<Result<T>> {
return service.post<T, Result<T>>(url, data);
},
// 发送PUT请求的方法,同样可指定数据类型T,并返回一个Promise对象
put<T = any>(url: string, data?: object): Promise<Result<T>> {
return service.put<T, Result<T>>(url, data);
},
// 发送DELETE请求的方法,同样可指定数据类型T,并返回一个Promise对象
delete<T = any>(
url: string
): Promise<Result<T>> {
return service.delete<T, Result<T>>(url);
},
};
2. 高级封装
相比基础封装,高级封装通过类的方式来创建实例,并将请求方法封装在类的原型上。
相比之下,这种方法更加灵活,可以创建多个不同配置的axios实例,也可以在实例中添加其他自定义的方法和属性。此外,高级封装还将请求方法统一封装在一个类中,结构更加清晰,易于维护和扩展。
TypeScript
// 先创建一个类,给类添加1个属性 instance代表axios的实例 构造函数传递配置 config配置比如全局的baseURL timeout
import axios from "axios";
import type {
AxiosInstance,
AxiosError,
AxiosResponse,
AxiosRequestConfig,
} from "axios";
// interface Result<T = any> {
// data: T;
// success: boolean;
// }
class Request {
// 限制创建的实例必须是axios的实例
private instance: AxiosInstance;
// 这个config是不能乱写的,axios对创建的配置有限制的
constructor(config: AxiosRequestConfig) {
this.instance = axios.create(config);
// 接下来配置axios实例身上的全局配置,比如拦截器
this.instance.interceptors.request.use(
(config: AxiosRequestConfig) => {
return config;
},
(error: AxiosError) => {
return Promise.reject(error);
}
);
this.instance.interceptors.response.use(
(response: AxiosResponse) => {
return response.data;
},
(error: AxiosError) => {
return Promise.reject(error);
}
);
}
// 公共方法,因为不知道返回值的类型
fetchData<T>(options: AxiosRequestConfig): Promise<T> {
// 将私有的instance上面发请求的操作,封装到这个实例方法request中,这个方法的返回值应该是一个promise对象
return new Promise((resolve, reject) => {
this.instance
.request<any, T>(options)
.then((res) => {
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}
// 调用上面封装的实例方法request,来实现get / post / delete / put 方法的快捷调用
get<T>(options: AxiosRequestConfig): Promise<T> {
return this.fetchData<T>({ ...options, method: "GET" });
}
post<T>(options: AxiosRequestConfig): Promise<T> {
return this.fetchData({ ...options, method: "POST" });
}
put<T>(options: AxiosRequestConfig): Promise<T> {
return this.fetchData({ ...options, method: "PUT" });
}
delete<T>(options: AxiosRequestConfig): Promise<T> {
return this.fetchData({ ...options, method: "DELETE" });
}
}
// 到处新new出来的实例
export const http = new Request({
baseURL: "https://mock.mengxuegu.com/mock/6323def2b4c53348ed2bc5d7/example",
});