目录
1. 在 `axios.create()` 中设置请求头特点:
2. 在请求拦截器(Response Interceptors)中设置请求头特点:
1. 请求拦截器(Request Interceptors)
2. 响应拦截器(Response Interceptors)
二、请求拦截器实现示例,Axios请求拦截器、响应拦截器中,分别应该设置什么,有什么作用?
2.2.4 return Promise.reject(error); 是什么?
2.2.4.1. Promise.reject(error) 的作用
前言
在现代 Web 开发中,前后端数据交互的 高效性 和 可维护性 至关重要。Axios 作为当前最流行的 HTTP 客户端之一,凭借其简洁的 API 设计、Promise 支持以及强大的 拦截器(Interceptors) 机制,成为开发者管理 HTTP 请求的首选工具。
拦截器允许开发者在请求发出前或响应返回后,统一添加逻辑处理,例如:
请求拦截器(Request Interceptors):自动添加 Token、修改请求头、数据加密等。
响应拦截器(Response Interceptors):全局错误处理、数据格式化、权限校验等。
本文将系统讲解 Axios 拦截器的使用方法,帮助开发者优化网络请求流程,减少重复代码,提升应用的可扩展性和稳定性。
Axios请求拦截器、响应拦截器固定的格式
首先要明确大概的固定格式和写法,这个是很重要的,我们要知道是由哪几部分组成,分别是干什么的
import axios from "axios";
// 创建axios实例
const instance = axios.create({
baseURL: "/api", //通用请求的地址前缀,有自己后端的话就换成自己后端服务的前缀
timeout: 10000, //限制请求超时时间
headers: { "X-Custom-Header": "foobar" },
});
// 添加请求拦截器(axios拦截器)
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
export default instance;
1、需要安装axios 然后引入
2、创建axios实例
3、添加请求拦截器(Request Interceptors)
4、添加响应拦截器(Response Interceptors)
注意:
在创建axios实例中可以设置请求头在请求拦截器(Response Interceptors)里面也可以设置请求头,那么有什么区别?
它们的主要区别在于作用范围和执行时机:
1. 在 `axios.create()` 中设置请求头特点:
这些是静态/默认的请求头
会在所有请求中自动添加
只在 Axios 实例创建时设置一次
适用于那些不会改变的全局头部
const instance = axios.create({
baseURL: "/api", //通用请求的地址前缀,有自己后端的话就换成自己后端服务的前缀
timeout: 10000, //限制请求超时时间
headers: { "X-Custom-Header": "foobar" },
});
2. 在请求拦截器(Response Interceptors)中设置请求头特点:
这些是动态的请求头
可以基于每次请求的具体情况设置
可以访问运行时数据(如从存储获取的 token)
适用于需要动态计算的头部(如认证 token)
可以在发送前最后修改请求配置
// 添加请求拦截器(axios拦截器)
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
//设置请求头
config.headers.Authorization = 'Bearer token123'; // 添加Token
return config; // 必须返回处理后的配置
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
表格对比
总结一下:
将通用的、不变的头部放在 `axios.create()` 中
将动态的、需要计算的头部(如认证 token)放在拦截器中
拦截器中的设置会合并/覆盖创建时的设置
一、Axios请求拦截器、响应拦截器分别是什么?
1. 请求拦截器(Request Interceptors)
在请求被发送到服务器之前拦截,常用于:
添加全局请求头(如
Authorization
Token)。修改请求数据(如序列化请求体)。
取消请求(如校验不通过时)。
// 添加请求拦截器(axios拦截器)
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
//设置请求头
config.headers.Authorization = 'Bearer token123'; // 添加Token
return config; // 必须返回处理后的配置
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
2. 响应拦截器(Response Interceptors)
在响应从服务器返回后拦截,常用于:
统一处理响应数据(如提取
data
字段)。全局错误处理(如 HTTP 状态码 401 跳转到登录页)。
转换响应格式(如日期格式化)。
axios.interceptors.response.use(
(response) => {
// 对响应数据做处理(默认Axios会包装一层data字段)
return response.data; // 直接返回核心数据
},
(error) => {
// 对响应错误做处理(如状态码非2xx)
if (error.response.status === 401) {
alert('登录过期,请重新登录!');
window.location.href = '/login';
}
return Promise.reject(error); // 继续抛出错误
}
);
二、请求拦截器实现示例,Axios请求拦截器、响应拦截器中,分别应该设置什么,有什么作用?
2.1.请求拦截器实现示例
const instance = axios.create({
//通用请求的地址前缀,有自己后端的话就换成自己后端服务的前缀
baseURL: "/api",
//限制请求超时时间
timeout: 10000,
//请求头
headers: { "X-Custom-Header": "foobar" },
// 请求方式,可以是 'post', 'put', 'delete' 等
method: 'get',
// GET 请求参数
params: {},
// POST 请求数据
data: {},
//设置 HTTP 基本认证
auth: { username: "user", password: "pass" },
//定义服务器返回的数据类型 如 json、blob、arraybuffer、document 等
responseType: "json",
//是否携带跨域请求的凭据
withCredentials: false,
//在发送请求或接收响应时对数据进行转换。
transformRequest: [function (data) { return JSON.stringify(data); }],
transformResponse: [function (data) { return JSON.parse(data); }],
});
大部分情况下,都只是会设置baseURL和timeout这两个参数,其他的使用情况非常少,这里就不做赘述了
2.2.请求拦截器中设置什么?
因为可以设置的东西太多,我这里就主要展示一下常用的几种情况
2.2.1 统一身份验证(token)
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
// 从存储获取认证信息
const token = getAuthToken();
// 如果token存在则添加到请求头
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
2.2.2 设置请求头
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
config.headers['Content-Type'] = 'application/json';
config.headers['X-Requested-With'] = 'XMLHttpRequest';
// 设置自定义请求头
config.headers['X-Custom-Header'] = 'your-custom-value';
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
2.2.3 加密请求体数据
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
// 加密函数
const encryptData = (data) => {
const key = CryptoJS.enc.Utf8.parse('your-secret-key'); // 16位密钥
const iv = CryptoJS.enc.Utf8.parse('your-iv-vector'); // 16位初始向量
if (typeof data === 'object') {
data = JSON.stringify(data);
}
const encrypted = CryptoJS.AES.encrypt(
CryptoJS.enc.Utf8.parse(data),
key,
{
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}
);
return encrypted.toString();
};
// 加密请求数据
if (config.data) {
config.data = {
encryptedData: encryptData(config.data)
};
}
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
2.2.4 return Promise.reject(error); 是什么?
首先,要知道当我们的拦截器抛出错误后,页面中的请求会去捕获这个错误
Promise.reject(error)
是 JavaScript Promise 的一个核心方法,它的作用是 明确表示当前操作失败,并返回一个被拒绝(rejected)的 Promise,同时携带错误信息(error
)。
2.2.4.1. Promise.reject(error)
的作用
表示异步操作失败:告诉调用方“这个请求/操作出错了”。
传递错误信息:将错误对象(
error
)传递给后续的.catch()
或try/catch
。中断 Promise 链:如果后续有
.then()
,它们会被跳过,直接进入.catch()
。
2.2.4.2. 在 Axios 拦截器中的用途
在 Axios 拦截器中,
return Promise.reject(error)
的主要目的是:
让错误继续传递:如果不
reject
,错误会被拦截器“吞掉”,外层axios.get().catch()
无法捕获。统一错误处理:可以在拦截器里先处理错误(如 401 跳转登录页),再让调用方处理剩余逻辑。
2.2.4.3 具体场景示例
(1) 请求拦截器的 Promise.reject
instance.interceptors.request.use(
(config) => {
if (!token) {
// 如果 token 不存在,主动 reject
return Promise.reject(new Error("缺少 token"));
}
return config;
},
(error) => {
// 请求发送前的错误(如网络断开)
return Promise.reject(error); // 继续抛出错误
}
);
页面中捕获错误的时候分情况,因为请求拦截器中抛出了两个错误,分别是
return Promise.reject(new Error("缺少 token"));以及return Promise.reject(error); // 继续抛出错误
情况一:
token
不存在(主动拒绝),则进入第一个回调 ,页面报错是 "缺少 token"
情况二 :
如果请求发送前的底层错误(如网络断开) 则进入第二个回调,页面报错是 "Network Error"; 或其他原生错误信息,看你自己具体是属于哪种类型导致请求失败。
axios.get("/api/data")
.then((res) => console.log(res))
.catch((err) => {
console.log(err.message); // 分情况
});
注意:
这里请求拦截器和响应拦截器抛错逻辑相同,下面不赘述响应拦截器中的 return.Promise.reject(error); 了
2.3.响应拦截器中设置什么?
2.3.1 成功响应处理(response
回调)
当服务器返回 2xx 状态码 时触发,通常用于:
instance.interceptors.response.use(function (response) {
// 成功响应处理
const res = response.data;
if (res.code === 200) {
return res.data; // 返回核心数据
} else {
// 非 200 当作错误处理
message.error(res.message || '操作失败');
return Promise.reject(res);
}
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
2.3.2 GET 请求缓存
对 GET 请求 的响应数据进行缓存,避免重复请求相同接口
instance.interceptors.response.use(
(response) => {
// 只缓存 GET 请求
if (response.config.method === 'get') {
const cacheKey = response.config.url + JSON.stringify(response.config.params);
localStorage.set(cacheKey, response.data); // 存储缓存数据
}
return response.data; // 返回核心数据
},
(error) => {
return Promise.reject(error);
}
);
2.3.3 判断并处理 Blob 响应(跳过处理)
当需要下载文件(如 Excel、PDF)时,后端通常返回 二进制流数据(Blob 类型)。Axios 需要明确知道这是一个二进制响应,而非普通的 JSON 数据。
为什么跳过Blob处理?
Blob 数据(如文件流)一旦被手动修改(如
response.data = ...
),文件会损坏无法下载。需要保留完整的
response
对象,包含 headers 等元信息(如文件名)。
作用:
确保 Axios 不会尝试解析二进制数据为 JSON/text。
保持原始的 Blob 数据完整性。
//关键配置:responseType: 'blob'
//在请求时声明此配置,告诉 Axios:
axios.get('/api/download-file', {
responseType: 'blob' // 明确要求返回 Blob 类型
})
//在拦截器中跳过数据处理
//在响应拦截器中,需判断是否为 Blob 响应,如果是则直接返回原始响应对象:
instance.interceptors.response.use(function (response) {
// 判断是否为 Blob 类型(文件下载)
if (response.config.responseType === 'blob' ||
response.headers['content-type']?.includes('application/octet-stream')) {
return response; // 直接返回原始响应,不处理数据
}
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
2.3.4 错误响应处理(error
回调)
当服务器返回 非 2xx 状态码 或 网络错误 时触发,下面的内容包括了很多种错误响应的情况
// 统一错误对象结构
const err = {
message: '',
code: '',
config: error.config,
response: error.response,
isAxiosError: true,
from: 'axios-interceptor'
};
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 1. 处理 HTTP 错误(4xx/5xx)
if (error.response) {
const { status, data } = error.response;
err.code = status;
// 1.1 根据状态码定制错误消息
switch (status) {
case 400:
err.message = data.message || '请求参数错误';
break;
case 401:
err.message = '登录已过期';
await handle401(error); // Token 过期处理(见下文)
break;
case 403:
err.message = data.message || '没有操作权限';
break;
case 404:
err.message = `请求资源不存在: ${error.config.url}`;
break;
case 500:
err.message = data.message || '服务器错误';
break;
default:
err.message = data.message || `请求失败 (${status})`;
}
// 1.2 业务逻辑错误(如 code=500 但 HTTP 状态码是 200)
if (data?.code && data.code !== 200) {
err.code = data.code;
err.message = data.message || '业务逻辑错误';
}
}
// 2. 处理网络错误(请求未到达服务器)
else if (error.request) {
err.code = 'NETWORK_ERROR';
err.message = error.message || '网络连接异常';
// 2.1 超时错误
if (error.code === 'ECONNABORTED') {
err.message = `请求超时 (${error.config.timeout}ms)`;
}
// 2.2 取消请求
else if (axios.isCancel(error)) {
err.code = 'REQUEST_CANCELED';
err.message = '请求已取消';
}
}
// 3. 其他未知错误
else {
err.code = 'UNKNOWN_ERROR';
err.message = error.message || '未知错误';
}
// 4. 统一错误提示(排除取消请求和静默请求)
if (!axios.isCancel(error) && !error.config?.silent) {
showErrorToast(err.message); // 使用 UI 组件提示
}
// 5. 日志上报(生产环境)
if (process.env.NODE_ENV === 'production') {
logErrorToService(err); // 上报到 Sentry/监控系统
}
return Promise.reject(error);
});
/**
* Token 过期处理
*
*/
async function handleTokenExpired(error) {
// 1. 清除旧 Token
localStorage.removeItem('token');
// 4. 跳转登录页
router.push({
path: '/login',
query: { redirect: router.currentRoute.fullPath }
});
// 3. 拒绝后续处理
return Promise.reject(new Error('登录已过期,请重新登录'));
}
2.4 移除拦截器
你也可以在需要的时候移除拦截器,避免对后续请求产生影响。
const requestInterceptor = instance.interceptors.request.use(function (config) {
// 添加自定义请求逻辑
return config;
});
// 移除请求拦截器
instance.interceptors.request.eject(requestInterceptor);
const responseInterceptor = instance.interceptors.response.use(function (response) {
// 处理响应数据
return response;
});
// 移除响应拦截器
instance.interceptors.response.eject(responseInterceptor);
三、拦截器集成应用
3.1多环境配置
1. 环境变量配置
在项目根目录的 .env
文件中定义环境变量:
# .env.development(开发环境)
VITE_API_BASE_URL = 'http://dev.example.com/api'
VITE_ENV = 'development'
# .env.production(生产环境)
VITE_API_BASE_URL = 'https://api.example.com'
VITE_ENV = 'production'
# .env.test(测试环境)
VITE_API_BASE_URL = 'https://test-api.example.com'
VITE_ENV = 'test'
2. 动态创建 Axios 实例
根据环境变量创建不同的实例配置:
// src/utils/request.js
import axios from 'axios';
const instance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL, // 自动读取对应环境的地址
timeout: 10000,
});
// 环境判断辅助函数
const isDev = import.meta.env.VITE_ENV === 'development';
const isProd = import.meta.env.VITE_ENV === 'production';
const istest = import.meta.env.VITE_ENV === 'test';
3. 请求拦截器(多环境逻辑)
可以根据自己的项目情况设置,我这里这是写一个demo做展示
instance.interceptors.request.use(
(config) => {
// 开发环境:打印请求日志
if (isDev) {
console.log('[Request]', config.method?.toUpperCase(), config.url);
// 这里你还可以设置其他逻辑 这里只是写个例子
}
// 生产环境:强制 HTTPS
if (isProd && !config.url.startsWith('https://')) {
console.warn('Production requests must use HTTPS!');
// 这里你还可以设置其他逻辑 这里只是写个例子
}
// 测试环境:
if (istest) {
//测试环境逻辑
}
// 所有环境:添加 Token
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
// 开发环境:详细日志
if (isDev) {
console.error('[Request Error]', error);
}
return Promise.reject(error);
}
);
4. 响应拦截器(多环境逻辑)
instance.interceptors.response.use(
(response) => {
// 开发环境:打印响应日志
if (isDev) {
console.log('[Response]', response.config.url, response.data);
}
return response.data;
},
(error) => {
// 开发环境:显示完整错误
if (isDev) {
console.error('[Response Error]', error.response?.data || error.message);
}
// 生产环境:简化错误提示
if (isProd) {
const errMessage = error.response?.data?.message || '系统繁忙,请稍后重试';
alert(errMessage); // 或用 UI 组件的友好提示
}
// 测试环境:上报错误到监控系统
if (istest) {
alert(error); // 或用 UI 组件的友好提示
}
return Promise.reject(error);
}
);
四、Axios请求拦截器、响应拦截器的执行顺序
4.1 请求拦截器
4.2 响应拦截器
五、Axios 请求拦截器和响应拦截器的完整流程图表展示
5.1 请求拦截器成功流程
5.2 请求拦截器报错流程
5.3 响应拦截器成功流程
5.4 响应拦截器报错流程
5.5 总表
涵盖 成功 和 报错 场景,便于直观理解:
六、总结
请求拦截器
用于修改请求配置(如 headers、timeout)。
添加认证信息、修改请求头等
避免阻塞性操作(如同步存储读写)。
响应拦截器
成功时:统一剥离冗余数据(如
response.data.data
→data
)。失败时:分类处理 HTTP 错误、网络错误、业务错误。
错误传递
始终用
Promise.reject(error)
抛出错误,确保能被.catch()
捕获。
Blob 处理
声明
responseType: 'blob'
,并在拦截器中跳过数据处理。(上文已经解释了为什么跳过blob处理 )