Axios拦截器:给你的请求加上"双保险"!

大家好,我是小杨。今天咱们不聊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('操作被用户取消');

我的最佳实践

  1. 按功能拆分拦截器
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);
  1. 提供拦截器移除功能
javascript 复制代码
const authInterceptor = apiClient.interceptors.request.use(addToken);

// 需要时移除
apiClient.interceptors.request.eject(authInterceptor);

总结

Axios拦截器就像给你的网络请求加上了"双保险":

  • 请求拦截器:统一处理认证、日志、参数处理
  • 响应拦截器:统一处理错误、重试、数据转换
  • 灵活组合:可以按需添加、移除拦截器
  • 错误处理:集中管理所有网络错误

记住:拦截器很强大,但也不要滥用。保持每个拦截器的职责单一,代码才会更清晰可维护!

⭐ 写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

✅ 一起探讨技术加qq交流群:906392632

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

相关推荐
晓得迷路了2 小时前
栗子前端技术周刊第 98 期 - NPM 生态遭受攻击、Rspack 1.5.3、Storybook 10 beta...
前端·javascript·css
江城开朗的豌豆2 小时前
解密DVA:React应用的状态管理利器
前端·javascript·react.js
码猿宝宝2 小时前
浏览器中javascript时间线,从加载到执行
开发语言·javascript·ecmascript
带娃的IT创业者2 小时前
《Python Web部署应知应会》No3:Flask网站的性能优化和实时监测深度实战
前端·python·flask
weixin_431600442 小时前
使用 vue-virtual-scroller 实现高性能传输列表功能总结
前端·javascript·vue.js
OEC小胖胖2 小时前
App Router vs. Pages Router:我应该如何选择?
开发语言·前端·前端框架·web·next.js
GDAL2 小时前
Knockout.js Google Closure Compiler 工具模块详解
javascript·knockout
软件技术NINI2 小时前
js趣味游戏 贪吃蛇
javascript
@菜菜_达2 小时前
后端post请求返回页面,在另一个项目中请求过来会出现的问题
javascript