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

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

相关推荐
Never_Satisfied1 小时前
在JavaScript / Node.js / 抖音小游戏中,使用tt.request通信
开发语言·javascript·node.js
一只小透明啊啊啊啊2 小时前
Java Web 开发的核心组件:Servlet, JSP,Filter,Listener
java·前端·servlet
你的人类朋友2 小时前
设计模式有哪几类?
前端·后端·设计模式
Yeats_Liao3 小时前
Go Web 编程快速入门 10 - 数据库集成与ORM:连接池、查询优化与事务管理
前端·数据库·后端·golang
啃火龙果的兔子3 小时前
前端八股文react篇
前端·react.js·前端框架
打小就很皮...3 小时前
React 实现 i18next 中英文切换集成
前端·react.js·i18next
拉不动的猪3 小时前
函数组件和异步组件
前端·javascript·面试
淮北4943 小时前
html + css +js
开发语言·前端·javascript·css·html
你的人类朋友3 小时前
适配器模式:适配就完事了bro!
前端·后端·设计模式
Setsuna_F_Seiei4 小时前
CocosCreator 游戏开发 - 利用 AssetsBundle 技术对小游戏包体积进行优化
前端·cocos creator·游戏开发