1、基本封装
封装一个Request的类,使得在外部可以调用此类的构造函数创建实例,创建的实例就对应axios实例,request/index.ts中代码如下:
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
class HDRequest {
// 创建这个类的目的:每个创建出的HDRequest的实例都对应一个axios实例
// 创建实例的方法:constructor()构造实例
instance: AxiosInstance;
constructor(config: AxiosRequestConfig) {
this.instance = axios.create(config);
}
// 二次封装网络请求的方法
request(config: AxiosRequestConfig) {
return this.instance.request(config);
}
}
export default HDRequest;
基本配置信息单独写在一个文件中,config/index.ts中代码如下:
export const BASE_URL = "http://codercba.com:8000";
export const TIME_OUT = 5000;
在service/index.ts中创建一个Request类的一个实例,并配置这个实例:
import HDRequest from "./request";
import { BASE_URL, TIME_OUT } from "./config/index";
const hdRequest = new HDRequest({
baseURL: BASE_URL,
timeout: TIME_OUT,
});
export default hdRequest;
在moduleds/home.ts中使用这个实例进行request:
import hdRequest from "..";
hdRequest
.request({
url: "/home/multidata",
})
.then((res) => {
console.log(res.data);
});
2、配置全局拦截器
request/index.ts
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
class HDRequest {
// 创建这个类的目的:每个创建出的HDRequest的实例都对应一个axios实例
// 创建实例的方法:constructor()构造实例
instance: AxiosInstance;
constructor(config: HDRequestConfig) {
this.instance = axios.create(config);
// 添加全局拦截器,每个实例都有
this.instance.interceptors.request.use(
(config) => {
console.log("全局请求成功的拦截");
return config;
},
(err) => {
console.log("全局请求失败的拦截");
return err;
}
);
this.instance.interceptors.response.use(
(config) => {
console.log("全局响应成功的拦截");
return config;
},
(err) => {
console.log("全局响应失败的拦截");
return err;
}
);
}
// 二次封装网络请求的方法
request(config: AxiosRequestConfig) {
return this.instance.request(config);
}
}
export default HDRequest;
3、为某一Request实例单独配置拦截器
新创建一个hdRequest2实例,在它的config中传入拦截器属性,但是axios的AxiosRequestConfig类型中并没有拦截器属性类型。
因此需要对request/index.ts中的构造函数中的config类型进行扩展(extends)
import HDRequest from "./request";
import { BASE_URL, TIME_OUT } from "./config/index";
const hdRequest = new HDRequest({
baseURL: BASE_URL,
timeout: TIME_OUT,
});
// 创建一个能够自定义拦截器的request实例
export const hdRequest2 = new HDRequest({
baseURL: "http://codercba.com:1888/airbnb/api",
timeout: 8000,
// 传入拦截器属性,但是axios的AxiosRequestConfig类型中并没有拦截器属性类型
// 因此需要对request/index.ts中的构造函数中的config类型进行扩展(extends)
interceptors: {
requestSuccessFn: (config) => {
console.log("爱彼迎的请求成功的拦截");
return config;
},
requestFailureFn: (err) => {
console.log("爱彼迎的请求失败的拦截");
return err;
},
responseSuccessFn: (res) => {
console.log("爱彼迎的响应成功的拦截");
return res;
},
responseFailureFn: (err) => {
console.log("爱彼迎的响应失败的拦截");
return err;
},
},
});
export default hdRequest;
request/index.ts
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
interface HDInteceptors {
requestSuccessFn?: (config: AxiosRequestConfig) => AxiosRequestConfig;
requestFailureFn?: (err: any) => any;
responseSuccessFn?: (config: AxiosResponse) => AxiosResponse;
responseFailureFn?: (err: any) => any;
}
interface HDRequestConfig extends AxiosRequestConfig {
interceptors?: HDInteceptors;
}
class HDRequest {
// 创建这个类的目的:每个创建出的HDRequest的实例都对应一个axios实例
// 创建实例的方法:constructor()构造实例
instance: AxiosInstance;
constructor(config: HDRequestConfig) {
this.instance = axios.create(config);
// 添加全局拦截器,每个实例都有
this.instance.interceptors.request.use(
(config) => {
console.log("全局请求成功的拦截");
return config;
},
(err) => {
console.log("全局请求失败的拦截");
return err;
}
);
this.instance.interceptors.response.use(
(config) => {
console.log("全局响应成功的拦截");
return config;
},
(err) => {
console.log("全局响应失败的拦截");
return err;
}
);
// 针对特定的hdRequest实例添加拦截器
this.instance.interceptors.request.use(
// 使用可选链,若config中没传入interceptors,那么这里是undefined
config.interceptors?.requestSuccessFn,
config.interceptors?.requestFailureFn
);
this.instance.interceptors.response.use(
config.interceptors?.responseSuccessFn,
config.interceptors?.requestFailureFn
);
}
// 二次封装网络请求的方法
request(config: AxiosRequestConfig) {
return this.instance.request(config);
}
}
export default HDRequest;
4、同一个request实例的不同网络请求设置不同的拦截器
modules/entire.ts中同一个实例在发送不同的request请求时一个配置了拦截器一个没配拦截器
import { hdRequest2 } from "..";
hdRequest2
.request({
url: "/entire/list",
params: {
offset: 0,
size: 20,
},
})
.then((res) => {
console.log(res);
});
hdRequest2
.request({
url: "/home/highscore",
interceptors: {
requestSuccessFn: (config) => {
console.log("/home/highscore请求成功的拦截");
return config;
},
responseSuccessFn: (res) => {
console.log("/home/highscore响应成功的拦截");
return res;
},
},
})
.then((res) => {
console.log(res);
});
对request/index.ts的request方法进行进一步封装,使之能够立即执行传进来的拦截器
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
interface HDInteceptors {
requestSuccessFn?: (config: AxiosRequestConfig) => AxiosRequestConfig;
requestFailureFn?: (err: any) => any;
responseSuccessFn?: (res: AxiosResponse) => AxiosResponse;
responseFailureFn?: (err: any) => any;
}
interface HDRequestConfig extends AxiosRequestConfig {
interceptors?: HDInteceptors;
}
class HDRequest {
// 创建这个类的目的:每个创建出的HDRequest的实例都对应一个axios实例
// 创建实例的方法:constructor()构造实例
instance: AxiosInstance;
constructor(config: HDRequestConfig) {
this.instance = axios.create(config);
// 添加全局拦截器,每个实例都有
this.instance.interceptors.request.use(
(config) => {
console.log("全局请求成功的拦截");
return config;
},
(err) => {
console.log("全局请求失败的拦截");
return err;
}
);
this.instance.interceptors.response.use(
(config) => {
console.log("全局响应成功的拦截");
return config;
},
(err) => {
console.log("全局响应失败的拦截");
return err;
}
);
// 针对特定的hdRequest实例添加拦截器
this.instance.interceptors.request.use(
config.interceptors?.requestSuccessFn,
config.interceptors?.requestFailureFn
);
this.instance.interceptors.response.use(
config.interceptors?.responseSuccessFn,
config.interceptors?.requestFailureFn
);
}
// 二次封装网络请求的方法
request(config: HDRequestConfig) {
// 为同一个request实例的不同网络请求设置不同的拦截器
// 不能将拦截器放在实例上,这样的话同一个实例的拦截器都是一样的了
// 只能判断传进来的config中是否设置了拦截器,若设置了就直接执行
// 执行this.instance.request(config)之前先执行requeSuccess,并更新config
if (config.interceptors?.requestSuccessFn) {
//立即调用拦截器函数执行requestSuccessFn
config = config.interceptors.requestSuccessFn(config);
}
// 由于执行完this.instance.request(config)之后才能对response结果进行拦截,是个异步的过程
// 创建一个Promise,先执行this.instance.request(config),然后等待结果,之后以结果作为拦截器函数的参数进行调用
return new Promise((resolve, reject) => {
this.instance
.request(config)
.then((res) => {
if (config.interceptors?.responseSuccessFn) {
res = config.interceptors.responseSuccessFn(res);
}
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}
}
export default HDRequest;