随着Axios版本的不同,类型也在改变,以后怎么写类型?
1. 封装Axios
将Axios封装成一个类,同时重新封装request方法
- 重新封装request有几个好处:
- 所有的请求将从我们定义的requet请求中发送,这样以后更换Axios工具,只需要将request方法重写就可以。
- 便于对请求的请求体和返回数据做拦截
- 方便统一配置请求的config
- 最基础版本
import axios from "axios";
import type { AxiosInstance } from "axios";
class MyAxios {
instance: AxiosInstance;
constructor(config: AxiosRequestConfig) {
this.instance = axios.create(config);
}
// 重新封装axios的request方法
async request(config: AxiosRequestConfig) {
return await this.instance.reques(config)
}
}
export default MyAxios;
- 发送请求
import MyAxios from "./request";
import { BASE_URL, TIME_OUT} from "./config"; // 配置文件
const myRequest1 = new MyAxios({
baseURL: BASE_URL,
timeout: TIME_OUT,
});
myRequest1
.request({
url: "/XXXXX",
})
.then((res) => {
// res为成功后返回的结果
});
2. 加入全局拦截器
- 加入全局拦截器后封装的Axios,调用方法与上面保持一致
import axios from "axios";
import type { AxiosInstance } from "axios";
class MyAxios {
instance: AxiosInstance;
constructor(config: AxiosRequestConfig) {
// 创建axios的实例
this.instance = axios.create(config);
// 全局请求拦截器
this.instance.interceptors.request.use(
(config) => {
// "全局请求拦截器:请求成功");
return config;
},
(error) => {
// ("全局请求拦截器:请求失败");
return error;
}
);
// 全局响应拦截器
this.instance.interceptors.response.use(
(res) => {
// ("全局响应拦截器:响应成功");
// res中含有axios中的很多东西,res.data :服务器返回的结果,
return res.data;
},
(error) => {
// ("全局响应拦截器:响应失败");
return error;
}
);
}
async request(config: AxiosRequestConfig) {
return await this.instance.request(config)
}
}
export default MyAxios;
- 发送请求
import MyAxios from "./request";
import { BASE_URL, TIME_OUT} from "./config"; // 配置文件
const myRequest1 = new MyAxios({
baseURL: BASE_URL,
timeout: TIME_OUT,
});
myRequest1
.request({
url: "/XXXXX",
})
.then((res) => {
// res变成了服务器发送会的数据,全局响应拦截器把Axios带的一些数据去掉了
});
3. 加入域拦截器
域拦截器是我自己想的名字,也可以说是实例拦截器
在实例中定义拦截方法
- 拦截的范围是一个
baseURL
,所以我称它为域拦截- 因为定义在一个
new MyAxios
实例中,也可以说是实例拦截器
- 给拦截器定义类型
import type { AxiosRequestConfig } from "axios";
// 自定义拦截器中的方法的类型
interface interceptorsFunction {
requestOnFulfilled?: (config: any) => any; // 请求成功
requestOnRejected?: (error: any) => any; // 请求失败
responseOnFulfilled?: (res: any) => any; // 响应成功
responseOnRejected?: (error: any) => any; // 响应失败
}
// 自定义拦截器类型。这里扩展了AxiosRequestConfig类型
interface MyAxiosRequestConfig extends AxiosRequestConfig {
MyInterceptors?: interceptorsFunction;
}
export { MyAxiosRequestConfig };
- 在实例中实现拦截器的方法
import MyAxios from "./request";
import { BASE_URL, TIME_OUT } from "./config";
import type { MyAxiosRequestConfig } from "./type";
const myRequest2 = new MyAxios({
baseURL: BASE_URL,
timeout: TIME_OUT,
// 域拦截器。给axios发送的自定义拦截器需要执行的功能
MyInterceptors: {
requestOnFulfilled: (config) => {
// ("自定义请求拦截器:请求成功");
return config
},
requestOnRejected: (error) => {
// ("自定义请求拦截器:请求失败");
return error
},
responseOnFulfilled: (res) => {
// ("自定义响应拦截器:响应成功");
return res
},
responseOnRejected: (error) => {
// ("自定义响应拦截器:响应失败");
return error
}
}
})
// 发送请求
myRequest.myRequest2
.request({
url: "XXXXXX",
})
.then((res) => {
// (res);
});
- 封装Axois
import axios from "axios";
import type { AxiosInstance } from "axios";
// 导入自定义拦截器的类型
import type { MyAxiosRequestConfig } from "./type";
class MyAxios {
instance: AxiosInstance;
constructor(config: MyAxiosRequestConfig) {
this.instance = axios.create(config);
// 全局请求拦截器
this.instance.interceptors.request.use(
(config) => {
// ("全局请求拦截器:请求成功");
return config;
},
(error) => {
// ("全局请求拦截器:请求失败");
return error;
}
);
// 全局响应拦截器
this.instance.interceptors.response.use(
(res) => {
// ("全局响应拦截器:响应成功");
return res.data;
},
(error) => {
// ("全局响应拦截器:响应失败");
return error;
}
);
// 请求中自定义的拦截器:实例的拦截器
// 判断config中是否有自定义的拦截器
if (config.MyInterceptors) {
// 把config中传过来的方法,绑定到实例上
this.instance.interceptors.request.use(
config.MyInterceptors.requestOnFulfilled,
config.MyInterceptors.requestOnRejected
);
this.instance.interceptors.response.use(
config.MyInterceptors.responseOnFulfilled,
config.MyInterceptors.responseOnRejected
);
}
}
async request(config: AxiosRequestConfig<T>) {
return await this.instance.request(config)
}
}
export default MyAxios;
4. 关于类型
requestOnFulfilled?: (config: any) => any; // 请求成功
定义拦截器类型中requestOnFulfilled
类型,看的教学视频中config
的类型是AxiosRequestConfig
,我设置后死活报错,看了一下axios
的类型定义文件中这里是InternalAxiosRequestConfig
,这里就涉及axios
的版本问题了,所以我觉得还是any
安全,万一明天更新版本又换了类型,这个代码就不通用了
5. 一次性拦截器
- 这又是我自己起的名字,这个拦截器针对具体的一个请求
例如:域 http:// 10.1.2.3:8000下面有很多资源,比如有/api/img、/api/text,一次性拦截器就是针对域下面的资源的,可能/api/img需要拦截器工作,而/api/text不需要拦截器,所以每个资源对拦截器的需求和功能是不一样的
- 封装Axios,主要是对request请求的改动,其他地方没有改动,省略代码,这个拦截器虽然是起到了拦截器的效果,其实就是引入了一段代码
import axios from "axios";
import type { AxiosInstance } from "axios";
// 导入自定义拦截器的类型
import type { MyAxiosRequestConfig } from "./type";
class MyAxios {
instance: AxiosInstance;
constructor(config: MyAxiosRequestConfig) {
this.instance = axios.create(config);
// 全局请求拦截器
// 全局响应拦截器
// 请求中自定义的拦截器:实例的拦截器
}
async request(config: MyAxiosRequestConfig) {
// config中是否定义了requestOnFulfilled这个方法
if (config.MyInterceptors?.requestOnFulfilled) {
// 如果有这个方法,把config对象处理一下
config = config.MyInterceptors.requestOnFulfilled(config);
}
return await this.instance
.request(config) // request方法返回Promise
.then((res) => {
// Promise是成功状态返回的res,如果需要处理就处理一下子
if (config.MyInterceptors?.responseOnFulfilled) {
res = config.MyInterceptors.responseOnFulfilled(res);
}
return res;
})
.catch((error) => { // Promise是失败状态或者异常,处理一下子
if (config.MyInterceptors?.responseOnRejected)
error = config.MyInterceptors.responseOnRejected(error);
return error;
});
}
}
export default MyAxios;
- 发送请求
const myRequest1 = new MyAxios({
baseURL: BASE_URL,
timeout: TIME_OUT,
});
// 发送请求
myRequest1
.request({
url: "XXXXXX",
// 定义一次性拦截器,只对 url: "XXXXX" 起效
MyInterceptors: {
requestOnFulfilled: (config) => {
// ("一次性拦截器,请求成功拦截");
return config;
},
responseOnFulfilled: (res) => {
// ("一次性拦截器,响应成功拦截");
return res;
},
responseOnRejected: (res) => {
// ("一次性拦截器,响应失败拦截");
return res;
},
},
})
.then((res) => {
// (res);
});
- 拦截器的类型定义与域拦截器中的一样就不重复了
6. 总结
- 全局拦截器:只要使用Axios发送请求就会执行
- 域拦截器:对实例中的一个
baseURL
(http://10.1.2.3:8080)负责 - 一次性拦截器:对单个request请求负责(/api/img、/api/text)
7. 以下是加上泛型定义和其他请求的Axios封装的完整版本
- 拦截器的类型定义
// /request/type.ts 文件
import type { AxiosRequestConfig } from "axios";
// 自定义拦截器中的方法的类型
interface interceptorsFunction<T = any> {
requestOnFulfilled?: (config: any) => any; // 请求成功
requestOnRejected?: (error: any) => any; // 请求失败
responseOnFulfilled?: (res: T) => T; // 响应成功
responseOnRejected?: (error: any) => any; // 响应失败
}
// 自定义拦截器类型
interface MyAxiosRequestConfig<T = any> extends AxiosRequestConfig {
MyInterceptors?: interceptorsFunction<T>;
}
export { MyAxiosRequestConfig };
- 常量的定义
- 这里的cLog是方便调试,不用的时候在这里设置为false就不打印了,打印的东西多了,看的眼花
// /config/index.ts
export const cLog = (message:any)=>{
// if (process.env.NODE_ENV !== 'production') return
// if (0) return
console.log(message)
}
export const BASE_URL = "http://codercba.com:8000"
export const TIME_OUT = 10000
- 封装后的Axios
// /request/index.ts
import axios from "axios";
import type { AxiosInstance } from "axios";
import { cLog } from "../config";
// 导入自定义拦截器的类型
import type { MyAxiosRequestConfig } from "./type";
class MyAxios {
instance: AxiosInstance;
constructor(config: MyAxiosRequestConfig) {
this.instance = axios.create(config);
// 全局请求拦截器
this.instance.interceptors.request.use(
(config) => {
cLog("全局请求拦截器:请求成功");
return config;
},
(error) => {
cLog("全局请求拦截器:请求失败");
return error;
}
);
// 全局响应拦截器
this.instance.interceptors.response.use(
(res) => {
cLog("全局响应拦截器:响应成功");
return res.data;
},
(error) => {
cLog("全局响应拦截器:响应失败");
return error;
}
);
// 请求中自定义的拦截器:实例的拦截器
if (config.MyInterceptors) {
this.instance.interceptors.request.use(
config.MyInterceptors.requestOnFulfilled,
config.MyInterceptors.requestOnRejected
);
this.instance.interceptors.response.use(
config.MyInterceptors.responseOnFulfilled,
config.MyInterceptors.responseOnRejected
);
}
}
async request<T = any>(config: MyAxiosRequestConfig<T>) {
if (config.MyInterceptors?.requestOnFulfilled) {
config = config.MyInterceptors.requestOnFulfilled(config);
}
return await this.instance
.request<any, T>(config)
.then((res) => {
if (config.MyInterceptors?.responseOnFulfilled) {
res = config.MyInterceptors.responseOnFulfilled(res);
}
return res;
})
.catch((error) => {
if (config.MyInterceptors?.responseOnRejected)
error = config.MyInterceptors.responseOnRejected(error);
return error;
});
}
get<T = any>(config: MyAxiosRequestConfig<T>) {
return this.request({ ...config, method: "get" });
}
post<T = any>(config: MyAxiosRequestConfig<T>) {
return this.request({ ...config, method: "post" });
}
delete<T = any>(config: MyAxiosRequestConfig<T>) {
return this.request({ ...config, method: "delete" });
}
put<T = any>(config: MyAxiosRequestConfig<T>) {
return this.request({ ...config, method: "put" });
}
patch<T = any>(config: MyAxiosRequestConfig<T>) {
return this.request({ ...config, method: "patch" });
}
}
export default MyAxios;
- 实例Axios
- myRequest1:只有全局拦截器
- myRequest2:有全局拦截器和域拦截器
// index.ts
import MyAxios from "./request";
import { BASE_URL, TIME_OUT, cLog } from "./config";
const myRequest1 = new MyAxios({
baseURL: BASE_URL,
timeout: TIME_OUT,
});
const myRequest2 = new MyAxios({
baseURL: BASE_URL,
timeout: TIME_OUT,
// 给axios发送的自定义拦截器需要执行的功能
MyInterceptors: {
requestOnFulfilled: (config) => {
cLog("自定义请求拦截器:请求成功");
return config
},
requestOnRejected: (error) => {
cLog("自定义请求拦截器:请求失败");
return error
},
responseOnFulfilled: (res) => {
cLog("自定义响应拦截器:响应成功");
return res
},
responseOnRejected: (error) => {
cLog("自定义响应拦截器:响应失败");
return error
}
}
})
export default { myRequest1,myRequest2 };
- 实际发送请求,以上都可以作为固定的使用,下面的部分就是我们每次要发送请求时编写的
// main.js
import myRequest from "../index";
import { cLog } from "../config";
myRequest.myRequest1
.request({
url: "XXXXX",
})
.then((res) => {
cLog(res);
});
myRequest.myRequest2
.request({
url: "XXXXX",
})
.then((res) => {
cLog(res);
});
myRequest.myRequest2
// 这里的类型是服务器返回数据的类型,感觉复杂这里用any
// 为什么这里的类型是服务器返回的数据类型?在全局拦截器中返回的是res.data
// 如果在其他拦截器中没有对res做出改变。这里应该是AxiosResponse类型
.request<类型>({
url: "XXXXX",
// 一次性拦截器
MyInterceptors: {
requestOnFulfilled: (config) => {
cLog("一次性拦截器,请求成功拦截");
return config;
},
responseOnFulfilled: (res) => {
cLog("一次性拦截器,响应成功拦截");
return res;
},
responseOnRejected: (res) => {
cLog("一次性拦截器,响应失败拦截");
return res;
},
},
})
.then((res) => {
cLog(res);
});
8. 拦截器的执行顺序
- 只有全局拦截器
全局请求拦截器:请求成功
全局响应拦截器:响应成功
- 有全局拦截器和域拦截器
自定义请求拦截器:请求成功
全局请求拦截器:请求成功
全局响应拦截器:响应成功
自定义响应拦截器:响应成功
- 全局、域、一次性拦截器
一次性拦截器,请求成功拦截
自定义请求拦截器:请求成功
全局请求拦截器:请求成功
全局响应拦截器:响应成功
自定义响应拦截器:响应成功
一次性拦截器,响应成功拦截