目 录
- 0、起因
- 1、冷静分析
- 2、一个简单粗糙但是能用的封装
0、起因
创建一个实例:
const service = axios.create({
baseURL: "/api",
timeout: 3e3,
withCredentials: true,
headers:{
"Content-Type": "application/json"
}
})
简单封装:
export default{
Post(url:string, params = {} ) {
return new Promise((resolve, reject) => {
service.post(url, params ).then(res => {
resolve(res.data);
}).catch(err => {
reject(err)
})
})
},
}
封装时放开 config 配置:
export default{
Post(url:string, params = {}, config: AxiosRequestConfig<any> = {}) {
return new Promise((resolve, reject) => {
service.post(url, params, config).then(res => {
resolve(res.data);
}).catch(err => {
reject(err)
})
})
},
}
源码里定义的几个接口:
主要信息:可以传一个 config 对象
request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
get<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
delete<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
head<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
options<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
post<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
put<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
像往常一样机械封装 axios实例
,封装 get、post、put、delete方法,之前都是秉持着“能用就行”的原则,力图简单快速,直接砍掉了方法自带的config参数,仅留下了 url、data 两个,其他配置参数(baseURL、headers…)开始就统一默认配置好。
但是随着不同需求的出现,问题也暴露了:请求不够灵活,没法单独定制 header
等信息。于是考虑封装时开放 config
参数,但是并不是每次都需要定制,大部分情况下默认就行。于是乎就纠结默认值的问题,之前没传的时候,底层获取到的是 undefined
,那么默认值 undefined
肯定没问题。问题在于,如果传入了 config
,那他是会替换掉实例的配置,还是合并?
1、冷静分析
一想肯定是合并,但是由于之前封装的时候失误,没有用实例而是直接用 axios 封装,导致出现 “初始配置丢失” 的假象,就打开源码一探究性(主要是我也很好奇他的很多东西,正好这个机会去䁖一䁖🤣)。
顺着源码,一路找到了 Axios
身上的 request
,然后还是自代码里找到了答案,实例自身会将初始配置对象存一份在 defaults
上,request
接到 config
后,会有一步合并的操作,也就是 mergeCofig
。源码的后边,也是用合并后的 config
发起请求,返回对应的 promise
对象。
axios/lib/core/Axios.js
class Axios {
constructor(instanceConfig) {
// ** 看这里
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
request(configOrUrl, config) {
if (typeof configOrUrl === 'string') {
config = config || {};
config.url = configOrUrl;
} else {
config = configOrUrl || {};
}
// ** 看这里
config = mergeConfig(this.defaults, config);
// 省略好几个字。。。
}
// 省略好多源码....
// ** 看这里
let newConfig = config;
i = 0;
while (i < len) {
const onFulfilled = requestInterceptorChain[i++];
const onRejected = requestInterceptorChain[i++];
try {
newConfig = onFulfilled(newConfig);
} catch (error) {
onRejected.call(this, error);
break;
}
}
try {
// ** 看这里
promise = dispatchRequest.call(this, newConfig);
} catch (error) {
return Promise.reject(error);
}
// 省略好多源码....
}
2、一个简单粗糙但是能用的封装
请求、响应拦截器可以更精致一点🤣
import axios, { AxiosRequestConfig } from "axios"
const service = axios.create({
baseURL: "/api",
timeout: 3e3,
withCredentials: true,
headers:{
"Content-Type": "application/json"
}
})
service.interceptors.request.use(config =>{
config.headers["token"] = "dont forget to carry the token"
return config
}, error=>{
})
service.interceptors.response.use((res)=>{
// 错误处理 token过期等
return res.data
}, error=>{
})
export {service}
export default {
Get(url: string, config: AxiosRequestConfig<any> = {}) {
return new Promise((resolve, reject) => {
service.get(url, config).then(res => {
resolve(res.data)
}).catch(err => {
reject(err)
})
})
},
Post(url:string, params = {}, config: AxiosRequestConfig<any> = {}) {
return new Promise((resolve, reject) => {
service.post(url, params, config).then(res => {
resolve(res.data);
}).catch(err => {
reject(err)
})
})
},
Put(url:string, params = {}, config: AxiosRequestConfig<any> = {}) {
return new Promise((resolve, reject) => {
service.put(url, params, config).then(res => {
resolve(res.data);
}).catch(err => {
reject(err)
})
})
},
Delete(url:string, config: AxiosRequestConfig<any> = {}) {
return new Promise((resolve, reject) => {
service.delete(url, config).then(res => {
resolve(res.data);
}).catch(err => {
reject(err)
})
})
},
}