Axios 拦截器时机 + 拦截器基础
前置:拦截器基础(是什么?为什么用?怎么注册?)
在讲 "拦截时机" 前,先明确拦截器核心基础 ------ 这是理解 "自动触发、触发时机" 的前提:
1. 拦截器的定义
Axios 拦截器(Interceptor)是 Axios 提供的全局钩子函数,分为「请求拦截器」和「响应拦截器」,可在 "请求发出前" 和 "响应返回后、业务代码处理前" 统一处理请求 / 响应,是 Axios 核心扩展能力。
2. 拦截器的核心价值
- 减少重复代码:如所有请求加 token、所有响应简化数据,无需在每个请求里重复编写;
- 统一管控流程:如全局处理加载动画、统一捕获错误(401 跳登录、500 服务器提示);
- 灵活控制请求 / 响应:如请求前校验参数、响应后过滤无用数据。
3. 拦截器的核心注册语法
推荐「实例拦截器」(避免污染全局),核心语法如下:
javascript
javascript
import axios from 'axios';
// 1. 创建自定义Axios实例(项目主流用法,隔离全局配置)
const service = axios.create({
baseURL: 'https://api.example.com', // 接口基准地址
timeout: 5000 // 请求超时时间(5秒)
});
// 2. 注册请求拦截器:请求发出前预处理
// 入参:成功回调(必须返回config,否则请求终止)、失败回调(必须返回reject)
const requestInterceptor = service.interceptors.request.use(
(config) => {
// 业务示例:统一给请求头加token(最常用场景)
const token = localStorage.getItem('token');
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
},
(error) => {
// 请求拦截失败(如配置错误),终止流程并抛错给后续catch
return Promise.reject(error);
}
);
// 3. 注册响应拦截器:响应返回后、业务处理前预处理
const responseInterceptor = service.interceptors.response.use(
(response) => {
// 业务示例:简化响应数据,业务层直接获取data(无需写response.data)
return response.data;
},
(error) => {
// 业务示例:统一错误处理(401未授权自动跳登录)
if (error.response?.status === 401) {
window.location.href = '/login'; // 跳转登录页
}
// 响应拦截失败,抛错给业务层catch
return Promise.reject(error);
}
);
// 4. 移除拦截器(可选:页面销毁/无需拦截时清理)
// service.interceptors.request.eject(requestInterceptor);
// service.interceptors.response.eject(responseInterceptor);
4. 拦截器的核心特点
- 链式执行:支持多拦截器,请求拦截器 "后注册先执行" (栈结构)、响应拦截器 "先注册先执行"(队列结构);
- 非侵入式:不修改原始请求 / 响应逻辑,仅做 "预处理 / 后处理";
- 可终止流程:返回
Promise.reject(error)可直接终止请求 / 响应流程,触发后续catch。
核心结论:拦截器触发时机(与 get/then/catch 的关系)
✅ 请求拦截器 :不是 "调用
axios.get()前" 执行,而是调用axios.get()后、Axios 真正发送 HTTP 请求前 执行;✅ 响应拦截器 :服务端返回响应后、
.then()/.catch()执行前 执行;✅ 整体符合 "请求 / 响应被 then/catch 处理前拦截" 的定义(请求拦截:拦截即将发出的请求;响应拦截:拦截即将交给业务的响应)。
一、纠正 "get 之前执行拦截器" 的误解
易混淆点:
- 拦截器是提前注册 (如项目初始化时),但仅调用
axios.get()(发起请求)时才触发;- 触发后先执行请求拦截器,再发送 HTTP 请求,而非 "未调用 get 就执行拦截器"。
通俗类比
- 注册请求拦截器 = 餐厅提前制定 "接单后核对订单" 的规则;
- 调用
axios.get()= 你向餐厅下单(发起请求);- 请求拦截器执行 = 服务员接单后、后厨做菜前,核对订单(加调料 / 确认地址);
- 实际发送请求 = 后厨做菜并送出;
- 响应拦截器执行 = 菜送回餐厅后、服务员交你前,检查菜品是否合格;
.then()/.catch()= 你吃到菜(处理成功)或吐槽(处理失败)。
二、完整执行链路(代码)
javascript
javascript
import axios from 'axios';
// 1. 创建自定义Axios实例(隔离全局配置,项目推荐)
const service = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000
});
// 2. 注册请求拦截器:get调用后、发请求前执行
service.interceptors.request.use(
(config) => {
console.log('🔴 请求拦截器执行(get调用后,发请求前)');
// 核心业务:给所有请求加token
const token = localStorage.getItem('token');
if (token) config.headers.Authorization = `Bearer ${token}`;
return config; // 必须返回配置,请求才能继续发送
},
(error) => {
console.error('🔴 请求拦截器执行失败');
return Promise.reject(error); // 终止请求,触发catch
}
);
// 3. 注册响应拦截器:响应返回后、then/catch前执行
service.interceptors.response.use(
(response) => {
console.log('🟢 响应拦截器执行(响应返回后,then/catch前)');
return response.data; // 简化数据,业务层直接用data
},
(error) => {
console.error('🟢 响应拦截器执行失败');
// 401统一处理:登录过期跳登录页
if (error.response?.status === 401) {
window.location.href = '/login';
alert('登录过期,请重新登录');
}
return Promise.reject(error); // 抛错给业务层catch
}
);
// 4. 调用get发起请求(触发整个拦截器+请求链路)
console.log('📌 开始调用service.get()');
service.get('/api/test', {
params: { id: 123 } // URL查询参数,最终拼接为?id=123
})
.then((data) => {
// 响应拦截器简化后,直接拿到服务端返回的原始数据
console.log('✅ then执行(响应拦截器后):', data);
})
.catch((error) => {
// 捕获全链路错误:拦截器失败/网络错误/服务端错误等
console.log('❌ catch执行(响应拦截器后):', error);
});
控制台输出顺序(成功场景)
📌 开始调用service.get()
🔴 请求拦截器执行(get调用后,发请求前)
// 【底层异步发送HTTP请求,等待服务端响应】
🟢 响应拦截器执行(响应返回后,then/catch前)
✅ then执行(响应拦截器后):{...} // 直接拿到简化后的data
控制台输出顺序(失败场景:401)
📌 开始调用service.get()
🔴 请求拦截器执行(get调用后,发请求前)
// 【底层发送请求,服务端返回401】
🟢 响应拦截器执行失败
❌ catch执行(响应拦截器后):Error: Request failed with status code 401
关键结论
- 请求拦截器:
axios.get()调用后、实际 HTTP 请求发送前执行(非 "写 get 代码前");- 响应拦截器:服务端返回响应后、
.then()/.catch()执行前执行;- 两者均实现 "请求 / 响应被 then/catch 处理前拦截" 的核心目标。
三、"拦截" 的具体行为(为什么要这个时机)
1. 请求拦截器(get 调用后,发请求前)
此时 Axios 已整合请求配置(url/params/headers 等),但未发送请求,可操作:
- ✅ 修改配置:加 token、补 baseURL、改请求方法;
- ✅ 校验拦截:token 过期 / 参数缺失时终止请求,避免无效请求;
- ✅ 附加逻辑:开启加载动画、记录请求日志、取消重复请求。
2. 响应拦截器(响应返回后,then/catch 前)
此时服务端已返回响应,业务代码未处理,可操作:
- ✅ 简化数据:仅返回
response.data,简化业务层代码;- ✅ 统一错误:401 跳登录、404 提示资源不存在、500 提示服务器错误;
- ✅ 数据预处理:过滤无用字段、格式化日期 / 分页数据;
- ✅ 兜底处理:网络错误 / 超时提示 "网络异常",提升体验。
四、拦截器执行时机边界表
| 拦截类型 | 触发时机 | 相对于axios.get()的位置 |
相对于.then()/.catch()的位置 |
核心可操作行为 |
|---|---|---|---|---|
| 请求拦截器 | 调用axios.get()后,实际发请求前 |
调用后,发请求前 | 远早于(请求阶段拦截) | 修改配置、校验参数、开启加载动画 |
| 响应拦截器 | 服务端返回响应后,.then()/.catch()前 |
调用 get 后的 "响应阶段" | 直接在前面(响应交给业务前拦截) | 简化数据、统一错误、关闭加载动画 |
五、总结:拦截器核心逻辑
- 注册与触发 :拦截器提前注册(实例 / 全局),调用
axios.get()/post()时自动触发,无需手动调用;- 时机核心 :调用
axios.get()→ 请求拦截器 → 发送请求 → 服务端响应 → 响应拦截器 →.then()/.catch();"处理前拦截":请求拦截 = 拦截即将发出的请求,响应拦截 = 拦截即将交给业务的响应;- 核心价值:实现请求 / 响应的全局统一处理,减少重复代码,提升流程管控能力。
简单记:拦截器是 Axios 给请求加的 "前置过滤器"、给响应加的 "后置处理器",axios.get()是触发这套过滤 / 处理流程的开关。