大家好,我是小杨。今天咱们不聊React,来聊聊Axios这个几乎每个前端项目都在用的HTTP客户端。特别是它的拦截器功能,简直就是网络请求的"守护神"!
记得我刚工作那会儿,每次发请求都要手动加token,处理错误,烦得要死。直到发现了Axios拦截器,我才真正体会到什么叫"开发体验飞起"!
什么是Axios拦截器?
简单说,拦截器就像是你家小区的保安:
- 请求拦截器:出门时的保安,检查你的出入证(token)
- 响应拦截器:回家时的保安,检查你带回来的东西是否安全
基础用法:快速上手
先来看看怎么设置一个简单的拦截器:
javascript
import axios from 'axios';
// 创建一个axios实例
const apiClient = axios.create({
baseURL: 'https://api.myapp.com',
timeout: 10000,
});
// 请求拦截器 - 出门保安
apiClient.interceptors.request.use(
(config) => {
// 在发送请求前做些事情
const token = localStorage.getItem('userToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
console.log('请求发出:', config.method, config.url);
return config;
},
(error) => {
// 对请求错误做些什么
console.error('请求出错:', error);
return Promise.reject(error);
}
);
// 响应拦截器 - 回家保安
apiClient.interceptors.response.use(
(response) => {
// 对响应数据做点什么
console.log('响应成功:', response.status);
return response.data; // 通常我们只需要data部分
},
(error) => {
// 对响应错误做点什么
console.error('响应出错:', error.response?.status);
return Promise.reject(error);
}
);
// 使用示例
async function getUserProfile(userId) {
try {
const userData = await apiClient.get(`/users/${userId}`);
return userData;
} catch (error) {
console.error('获取用户信息失败:', error);
throw error;
}
}
实战技巧:我踩过的坑
1. Token过期自动刷新
这是我遇到过最实用的场景:
javascript
let isRefreshing = false;
let failedQueue = [];
// 响应拦截器增强版
apiClient.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
// 如果正在刷新token,将请求加入队列
return new Promise((resolve, reject) => {
failedQueue.push({ resolve, reject });
}).then(() => {
return apiClient(originalRequest);
});
}
originalRequest._retry = true;
isRefreshing = true;
try {
// 刷新token
const refreshToken = localStorage.getItem('refreshToken');
const { data } = await axios.post('/auth/refresh', { refreshToken });
localStorage.setItem('userToken', data.accessToken);
apiClient.defaults.headers.Authorization = `Bearer ${data.accessToken}`;
// 重试所有失败的请求
failedQueue.forEach((promise) => promise.resolve());
failedQueue = [];
return apiClient(originalRequest);
} catch (refreshError) {
// 刷新失败,清空所有状态
failedQueue.forEach((promise) => promise.reject(refreshError));
localStorage.removeItem('userToken');
localStorage.removeItem('refreshToken');
window.location.href = '/login';
return Promise.reject(refreshError);
} finally {
isRefreshing = false;
}
}
return Promise.reject(error);
}
);
2. 请求重试机制
有时候网络不稳定,自动重试很实用:
javascript
apiClient.interceptors.response.use(
(response) => response,
async (error) => {
const config = error.config;
const MAX_RETRY = 3;
if (!config || !config.retry) {
config.retry = 0;
}
if (config.retry < MAX_RETRY) {
config.retry += 1;
// 指数退避重试
const delay = Math.pow(2, config.retry) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
return apiClient(config);
}
return Promise.reject(error);
}
);
3. 全局加载状态管理
javascript
let activeRequests = 0;
apiClient.interceptors.request.use((config) => {
activeRequests++;
if (activeRequests === 1) {
// 显示全局loading
document.dispatchEvent(new CustomEvent('loadingStart'));
}
return config;
});
apiClient.interceptors.response.use(
(response) => {
activeRequests--;
if (activeRequests === 0) {
document.dispatchEvent(new CustomEvent('loadingEnd'));
}
return response;
},
(error) => {
activeRequests--;
if (activeRequests === 0) {
document.dispatchEvent(new CustomEvent('loadingEnd'));
}
return Promise.reject(error);
}
);
常见坑点及解决方案
1. 拦截器执行顺序
javascript
// 注意:拦截器按照添加顺序执行
apiClient.interceptors.request.use((config) => {
console.log('第一个拦截器');
return config;
});
apiClient.interceptors.request.use((config) => {
console.log('第二个拦截器'); // 后添加的先执行!
return config;
});
2. 取消请求
javascript
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
// 设置取消token
apiClient.get('/some-api', {
cancelToken: source.token
});
// 需要时取消请求
source.cancel('操作被用户取消');
我的最佳实践
- 按功能拆分拦截器:
javascript
// auth-interceptor.js
export const setupAuthInterceptor = (client) => {
client.interceptors.request.use(addToken);
};
// error-interceptor.js
export const setupErrorInterceptor = (client) => {
client.interceptors.response.use(handleSuccess, handleError);
};
// 在主文件中组合使用
setupAuthInterceptor(apiClient);
setupErrorInterceptor(apiClient);
- 提供拦截器移除功能:
javascript
const authInterceptor = apiClient.interceptors.request.use(addToken);
// 需要时移除
apiClient.interceptors.request.eject(authInterceptor);
总结
Axios拦截器就像给你的网络请求加上了"双保险":
- ✅ 请求拦截器:统一处理认证、日志、参数处理
- ✅ 响应拦截器:统一处理错误、重试、数据转换
- ✅ 灵活组合:可以按需添加、移除拦截器
- ✅ 错误处理:集中管理所有网络错误
记住:拦截器很强大,但也不要滥用。保持每个拦截器的职责单一,代码才会更清晰可维护!
⭐ 写在最后
请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.
✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式
✅ 认为我部分代码过于老旧,可以提供新的API或最新语法
✅ 对于文章中部分内容不理解
✅ 解答我文章中一些疑问
✅ 认为某些交互,功能需要优化,发现BUG
✅ 想要添加新功能,对于整体的设计,外观有更好的建议
✅ 一起探讨技术加qq交流群:906392632
最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!