Axios拦截器:前端通信的交通警察[特殊字符]
文章目录
- Axios拦截器:前端通信的"交通警察"🚦
- 引言:为什么需要拦截器?
- 拦截器的作用与好处
- 作用概览表
- 五大核心好处
- 拦截器的工作原理
- 流程图解
- 原理详解
- 拦截器的多种写法与实践
- 1. 基础写法
- 2. 类封装写法(更工程化)
- 3. 多实例不同拦截策略
- 高级应用场景
- 1. 重试机制
- 2. 请求取消
- 3. 性能监控
- 拦截器最佳实践
- 1. 组织架构建议
- 2. 代码示例:模块化拦截器
- 3. 注意事项
- 总结:拦截器的核心价值

Axios拦截器:前端通信的"交通警察"🚦
引言:为什么需要拦截器?
想象一下你是一个城市的交通管理员,每天有成千上万的车辆(HTTP请求)在城市(你的应用)中穿梭。如果没有交通信号灯和交警(拦截器),这些车辆会乱成一团:
- 每辆车都要自己找路(每个请求手动处理)
- 遇到事故(错误)没有统一处理
- 特殊车辆(特殊请求)没有优先通道
Axios拦截器就像是这个城市的智能交通管理系统,它能:
- 统一管理所有进出的请求和响应
- 自动处理重复性工作(如添加token)
- 集中处理错误和异常
- 监控和记录请求过程
拦截器的作用与好处
作用概览表
拦截器类型 | 主要作用 | 典型应用场景 |
---|---|---|
请求拦截器 | 在请求发送前处理 | 添加认证token、设置请求头、参数加密 |
响应拦截器 | 在响应返回后处理 | 统一错误处理、数据格式化、响应解密 |
五大核心好处
- 代码复用:避免在每个请求中重复相同代码
- 集中管理:统一处理认证、错误等逻辑
- 流程控制:可以中断或修改请求/响应流程
- 增强可读性:业务代码更专注于业务本身
- 便于维护:修改拦截逻辑只需改一处
拦截器的工作原理
流程图解
[发起请求] →
[请求拦截器] →
[实际发送请求] →
[服务器处理] →
[响应返回] →
[响应拦截器] →
[最终数据处理]
原理详解
Axios内部维护了两个拦截器链(数组):
- 请求拦截器链:按添加顺序执行(先添加先执行)
- 响应拦截器链:按添加逆序执行(先添加后执行)
当发起请求时,Axios会:
- 创建一个Promise链
- 依次执行请求拦截器
- 发送实际HTTP请求
- 依次执行响应拦截器
- 返回最终处理结果
拦截器的多种写法与实践
1. 基础写法
// 添加请求拦截器
axios.interceptors.request.use(function (config) {// 在发送请求之前做些什么console.log('请求拦截器 - 处理请求配置', config);config.headers.Authorization = 'Bearer your_token'; // 添加tokenreturn config; // 必须返回处理后的config}, function (error) {// 对请求错误做些什么console.log('请求拦截器 - 错误处理', error);return Promise.reject(error);}
);// 添加响应拦截器
axios.interceptors.response.use(function (response) {// 对响应数据做点什么 (2xx范围内的状态码)console.log('响应拦截器 - 处理成功响应', response);return response.data; // 通常我们只需要data部分}, function (error) {// 对响应错误做点什么 (超出2xx范围的状态码)console.log('响应拦截器 - 处理错误响应', error);if (error.response.status === 401) {// 处理未授权错误window.location.href = '/login';}return Promise.reject(error);}
);
2. 类封装写法(更工程化)
class HttpInterceptor {constructor() {this.instance = axios.create({baseURL: 'https://api.example.com',timeout: 10000});this.setupInterceptors();}setupInterceptors() {// 请求拦截this.instance.interceptors.request.use(config => {// 请求前添加loadingthis.showLoading();// 添加认证信息const token = localStorage.getItem('token');if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;},error => {this.hideLoading();return Promise.reject(error);});// 响应拦截this.instance.interceptors.response.use(response => {this.hideLoading();// 处理成功响应if (response.data.code === 200) {return response.data.data;} else {// 业务逻辑错误this.handleBusinessError(response.data);return Promise.reject(response.data);}},error => {this.hideLoading();// 处理HTTP错误this.handleHttpError(error);return Promise.reject(error);});}showLoading() { /* 显示加载动画 */ }hideLoading() { /* 隐藏加载动画 */ }handleBusinessError(data) {const errorMap = {401: '未授权,请重新登录',403: '拒绝访问',404: '请求资源不存在',500: '服务器错误'};const message = errorMap[data.code] || '未知错误';alert(message);}handleHttpError(error) {if (error.response) {// 服务器返回了响应但状态码不在2xx范围console.error('响应错误:', error.response.status);} else if (error.request) {// 请求已发出但没有收到响应console.error('无响应:', error.request);} else {// 发送请求时出了点问题console.error('请求错误:', error.message);}}
}// 使用示例
const http = new HttpInterceptor();
http.instance.get('/user/123');
3. 多实例不同拦截策略
// 创建两个不同的axios实例
const publicApi = axios.create({baseURL: 'https://api.example.com/public'
});const privateApi = axios.create({baseURL: 'https://api.example.com/private'
});// 公共API拦截器 - 简单处理
publicApi.interceptors.response.use(response => response.data,error => {console.error('公共API错误:', error);return Promise.reject(error);}
);// 私有API拦截器 - 复杂处理
privateApi.interceptors.request.use(config => {const token = localStorage.getItem('token');if (!token) {throw new Error('无访问令牌');}config.headers.Authorization = `Bearer ${token}`;return config;
});privateApi.interceptors.response.use(response => response.data,error => {if (error.response.status === 401) {// token过期,跳转登录window.location.href = '/login?expired=1';}return Promise.reject(error);}
);
高级应用场景
1. 重试机制
axios.interceptors.response.use(response => response,error => {const config = error.config;// 设置重试次数,默认为0config.__retryCount = config.__retryCount || 0;// 检查是否超过最大重试次数(3次)if (config.__retryCount >= 3) {return Promise.reject(error);}// 增加重试计数器config.__retryCount += 1;// 创建新的Promise来处理指数退避const delay = new Promise(resolve => {setTimeout(() => resolve(), 1000 * config.__retryCount);});// 返回Promise,在延迟后重试请求return delay.then(() => axios(config));}
);
2. 请求取消
// 创建一个Map来存储请求标识和取消函数
const pendingRequests = new Map();// 生成请求标识
const generateReqKey = (config) => {const { method, url, params, data } = config;return [method, url, JSON.stringify(params), JSON.stringify(data)].join('&');
};// 请求拦截器 - 添加取消逻辑
axios.interceptors.request.use(config => {const requestKey = generateReqKey(config);if (pendingRequests.has(requestKey)) {// 如果请求已存在,取消前一个pendingRequests.get(requestKey).cancel('重复请求');}// 创建取消令牌config.cancelToken = new axios.CancelToken(cancel => {pendingRequests.set(requestKey, { cancel });});return config;
});// 响应拦截器 - 移除已完成请求
axios.interceptors.response.use(response => {const requestKey = generateReqKey(response.config);pendingRequests.delete(requestKey);return response;
}, error => {if (axios.isCancel(error)) {console.log('请求被取消:', error.message);return Promise.reject(error);}const requestKey = generateReqKey(error.config);if (error.config) {pendingRequests.delete(requestKey);}return Promise.reject(error);
});
3. 性能监控
// 请求开始时间记录
axios.interceptors.request.use(config => {config.metadata = { startTime: new Date() };return config;
});// 响应时间计算
axios.interceptors.response.use(response => {const endTime = new Date();const duration = endTime - response.config.metadata.startTime;console.log(`请求 ${response.config.url} 耗时 ${duration}ms`);// 可以上报到性能监控系统reportPerformance({url: response.config.url,method: response.config.method,duration: duration,status: response.status});return response;},error => {if (error.config) {const endTime = new Date();const duration = endTime - error.config.metadata.startTime;console.error(`请求 ${error.config.url} 失败,耗时 ${duration}ms`);reportPerformance({url: error.config.url,method: error.config.method,duration: duration,status: error.response?.status || 0,error: error.message});}return Promise.reject(error);}
);
拦截器最佳实践
1. 组织架构建议
/src/apiinterceptors/request/auth.js # 认证处理loading.js # 加载状态log.js # 请求日志response/error.js # 错误处理format.js # 数据格式化index.js # 整合所有拦截器services/ # 各个API模块http.js # axios实例创建
2. 代码示例:模块化拦截器
// http.js - 创建axios实例
import axios from 'axios';const http = axios.create({baseURL: process.env.VUE_APP_API_BASE_URL,timeout: 30000
});export default http;// interceptors/request/auth.js
export default function addAuthToken(config) {const token = localStorage.getItem('token');if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;
}// interceptors/response/error.js
export default function handleError(error) {if (error.response) {switch (error.response.status) {case 400:console.error('请求错误');break;case 401:console.error('未授权,请重新登录');break;case 403:console.error('拒绝访问');break;case 404:console.error('请求资源不存在');break;case 500:console.error('服务器错误');break;default:console.error(`未知错误: ${error.response.status}`);}}return Promise.reject(error);
}// interceptors/index.js - 整合拦截器
import http from '../../http';
import addAuthToken from './request/auth';
import handleError from './response/error';// 请求拦截器
http.interceptors.request.use(addAuthToken);// 响应拦截器
http.interceptors.response.use(response => response.data, // 直接返回datahandleError
);export default http;
3. 注意事项
-
执行顺序:多个拦截器按添加顺序执行
- 请求拦截器:先添加的先执行
- 响应拦截器:先添加的后执行
-
错误处理:确保拦截器中错误被正确传递
- 使用
Promise.reject
传递错误 - 不要"吞掉"错误
- 使用
-
内存泄漏:
- 使用
eject
移除不再需要的拦截器
const interceptor = axios.interceptors.request.use(...); axios.interceptors.request.eject(interceptor);
- 使用
-
避免副作用:
- 不要在一个拦截器中修改另一个拦截器的行为
- 保持拦截器职责单一
-
性能考虑:
- 拦截器中的逻辑应尽量轻量
- 避免在拦截器中执行耗时操作
总结:拦截器的核心价值
Axios拦截器就像是你应用HTTP通信的"中间件管道",它提供了统一的入口和出口来处理所有请求和响应。通过合理使用拦截器,你可以:
- 标准化:统一处理认证、错误、loading状态等
- 解耦:将基础设施逻辑与业务逻辑分离
- 增强:添加重试、缓存、监控等高级功能
- 简化:减少业务代码中的重复逻辑
记住,强大的能力伴随着责任,拦截器虽然强大,但也需要合理设计和使用,避免过度复杂化你的请求处理流程。