如何优化Axios拦截器性能及排查网络/服务器性能问题?
Axios拦截器性能优化与网络排查问题
我的Axios请求拦截器运行耗时极长,表现为加载停滞,浏览器显示“paused in debugger”提示,开发者工具自动定位到utils.js中高亮的代码段:
// Iterate over object keys const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj); const len = keys.length; let key; for (i = 0; i < len; i++) { key = keys[i]; fn.call(null, obj[key], key, obj); } } }
所有使用该拦截器的请求都会出现此问题,相关代码如下:
Axios实例与拦截器
import axios from 'axios'; const instance = axios.create({ baseURL: 'http://localhost:3005', withCredentials: true, timeout: 5000, // 设置5秒超时 }); // 添加请求拦截器校验access token有效性 instance.interceptors.request.use(async (config) => { const token = localStorage.getItem("accessToken"); try { // 调用/checkToken接口校验token await instance.get('/checkToken', { headers: { 'Authorization': `Bearer ${token}` }, withCredentials: true }); console.log('已发送checkToken请求!') } catch (error) { // token无效时调用/refreshToken接口获取新token const response = await instance.post('/refreshToken', { headers: { 'Authorization': `Bearer ${token}` }, withCredentials: true }); console.log('已发送refreshToken请求!') // 为后续请求设置新的Authorization头 const newToken = response.data.newAccessToken; config.headers['Authorization'] = `Bearer ${response.data.newAccessToken}`; console.log(newToken); } return config; }, (error) => { // 处理请求错误 return Promise.reject(error); }); export default instance;
后端checkToken与refreshToken接口
export const checkToken = (req, res) => { // 从请求头获取token const token = req.headers.authorization.split(' ')[1]; try { // 校验并解码token const decodedToken = jwt.verify(token, process.env.JWT_SECRET); // token有效则返回成功响应 res.status(200).json({ message: 'Token is valid' }); } catch (error) { // token过期或无效返回错误响应 res.status(401).json({ error: 'Invalid or expired token' }); } }; ----------- export const refreshHandle = async (req,res,next) => { try { const rToke = req.headers.cookie if(!rToke) return res.status(401).json({message:'unauthorized'}); const refreshToken = rToke.split('=')[1]; const decodedRefreshToken = jwt.verify( refreshToken, process.env.REFRESH_TOKEN_SECRET ); console.log(decodedRefreshToken, 'refresh token已验证!') const newAccessToken = jwt.sign( { userId: decodedRefreshToken.userId }, process.env.JWT_SECRET, { expiresIn: "3m" } ); // res.cookie("refreshToken", newRefreshToken, { httpOnly: true }); res.json({token : newAccessToken}) next(); } catch (err) { const error = new HttpError('Authentication failed', 401); return next(error); } }
使用该Axios实例的Redux动作
export const saveProductAction = (productId) => async (dispatch, getState) => { const { token } = getState().auth; console.log(token); const config = { headers: { Authorization: 'Bearer ' + token } }; const url = `http://localhost:3005/product/${productId}/save`; try { const response = await instance.put(url, null, config); console.log(response.data) dispatch(saveProduct(response.data.productId)); } catch (error) { console.error(error); console.error(error?.response?.data ?? error.message); } };
请问如何优化Axios拦截器的运行性能?另外能否提供排查网络问题的相关建议?
优化方案与排查建议
一、拦截器性能优化
1. 解决拦截器循环触发问题(核心原因)
当前拦截器内使用带拦截器的instance发送checkToken和refreshToken请求,会再次触发同一请求拦截器,形成无限递归循环,直接导致请求卡死。解决方法:
- 创建一个不带拦截器的Axios实例,专门用于token校验和刷新:
// 新建无拦截器的实例 const axiosNoInterceptor = axios.create({ baseURL: 'http://localhost:3005', withCredentials: true, timeout: 5000 }); // 在拦截器中改用这个实例发请求 instance.interceptors.request.use(async (config) => { const token = localStorage.getItem("accessToken"); if (!token) return config; try { await axiosNoInterceptor.get('/checkToken', { headers: { 'Authorization': `Bearer ${token}` }, withCredentials: true }); } catch (error) { // 同样用axiosNoInterceptor发refresh请求 const response = await axiosNoInterceptor.post('/refreshToken', {}, { headers: { 'Authorization': `Bearer ${token}` }, withCredentials: true }); const newToken = response.data.token; config.headers['Authorization'] = `Bearer ${newToken}`; localStorage.setItem("accessToken", newToken); } return config; });
2. 减少不必要的网络请求
每次请求都调用checkToken接口完全没必要,可改为本地校验token过期时间:
- 存储token时同时保存过期时间(解码JWT的
exp字段,转成时间戳) - 拦截器中先判断token是否即将过期,只有过期时才调用refresh接口,无需每次都调用checkToken
3. 修复请求参数错误
当前refreshToken的post请求把headers放在了data参数里(第二个参数),正确的headers应该放在第三个参数的config中,否则后端无法正确获取headers:
// 错误写法 await instance.post('/refreshToken', { headers: ... }); // 正确写法 await axiosNoInterceptor.post('/refreshToken', {}, { headers: { 'Authorization': `Bearer ${token}` }, withCredentials: true });
4. 增加边界判断
拦截器开头先判断token是否存在,不存在直接返回config,避免无效请求:
const token = localStorage.getItem("accessToken"); if (!token) { return config; }
二、网络问题排查建议
- 查看Network面板:打开浏览器开发者工具的Network标签,筛选XHR/Fetch请求,查看
checkToken、refreshToken以及业务请求的状态码、响应时间、请求/响应内容,确认是否有请求卡住、重复发送或报错。 - 检查控制台日志:查看Console标签的错误信息,是否有无限循环的请求报错、token解析错误等。
- 直接调用后端接口:用Postman或curl直接调用
checkToken和refreshToken接口,测试接口本身的响应速度和正确性,排除后端性能问题。 - 检查调试断点:确认是否在utils.js或相关代码中设置了未关闭的debugger断点,导致每次请求都触发暂停。
- 测试超时设置:当前timeout设为5000ms,可临时调低或调高,观察是否是超时导致的停滞,同时检查后端接口是否存在超时未响应的情况。
内容的提问来源于stack exchange,提问作者novicecoder
相关产品推荐
相关产品推荐

