前端知识点-axios 的拦截器原理及应用,并简单手写核心逻辑
Axios 拦截器允许在请求和响应阶段插入处理逻辑。以下是其原理、实现及优雅应用:
拦截器原理
- 队列结构:请求和响应拦截器分别存储在队列中,请求拦截器在发送请求前执行,响应拦截器在接收响应后执行。
- Promise 链:通过构建 Promise 链,依次执行拦截器处理函数。请求拦截器按添加顺序执行,响应拦截器同样按添加顺序执行。
- 错误处理:任一拦截器返回 rejected Promise 会跳过后续拦截器,直接进入错误处理。
手写核心逻辑
class InterceptorManager {
constructor() {
this.handlers = [];
}
use(fulfilled, rejected) {
this.handlers.push({ fulfilled, rejected });
}
}
class Axios {
constructor() {
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager(),
};
}
request(config) {
let chain = [this.dispatchRequest, undefined]; // 初始链
// 请求拦截器按顺序插入到链首
this.interceptors.request.handlers.reverse().forEach(interceptor => {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
// 响应拦截器按顺序添加到链尾
this.interceptors.response.handlers.forEach(interceptor => {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
let promise = Promise.resolve(config);
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
}
dispatchRequest(config) {
// 模拟实际请求
return new Promise(resolve => {
setTimeout(() => resolve({ data: config.url, status: 200 }), 100);
});
}
}
// 使用示例
const axios = new Axios();
// 添加请求拦截器
axios.interceptors.request.use(config => {
console.log('请求拦截器1');
config.headers = { Authorization: 'Bearer token' };
return config;
});
axios.interceptors.request.use(config => {
console.log('请求拦截器2');
return config;
});
// 添加响应拦截器
axios.interceptors.response.use(response => {
console.log('响应拦截器1');
return response.data; // 返回处理后的数据
});
axios.interceptors.response.use(response => {
console.log('响应拦截器2');
return response;
});
axios.request({ url: '/api/data' })
.then(data => console.log('成功:', data))
.catch(err => console.error('失败:', err));
拦截器应用场景
- 请求处理:
- 添加认证头:config.headers.Authorization = 'Bearer token'
- 请求数据格式化:转换数据格式或加密
- 响应处理:
- 统一错误处理:检查状态码,处理 401 跳转登录
- 数据解析:提取响应数据,如 return response.data
- 全局Loading:
- 请求前显示 Loading,响应后隐藏
优雅实践建议
- 模块化:将拦截器拆分到独立文件,便于维护。
// auth-interceptor.js
export function requestAuth(config) {
config.headers.Auth = 'xxx';
return config;
}
错误处理:统一在响应拦截器中处理错误。
axios.interceptors.response.use(null, err => {
if (err.response.status === 401) {
redirectToLogin();
}
return Promise.reject(err);
});
- 避免副作用:拦截器应保持纯净,避免修改外部状态。
- 取消拦截器:通过 eject 移除不必要的拦截器。
const interceptor = axios.interceptors.request.use(...);
axios.interceptors.request.eject(interceptor);
执行顺序示例
请求拦截器1 → 请求拦截器2 → 发送请求 → 响应拦截器1 → 响应拦截器2 → 最终结果
通过合理使用拦截器,可提升代码复用性,统一管理请求/响应逻辑,使代码更简洁易维护。