Axios请求拦截器、响应拦截器的分析和总结

发布于:2025-06-29 ⋅ 阅读:(15) ⋅ 点赞:(0)

目录

Axios请求拦截器、响应拦截器固定的格式

1. 在 `axios.create()` 中设置请求头特点:

2. 在请求拦截器(Response Interceptors)中设置请求头特点:

表格对比

总结一下:

一、Axios请求拦截器、响应拦截器分别是什么?

1. 请求拦截器(Request Interceptors)

2. 响应拦截器(Response Interceptors)

二、请求拦截器实现示例,Axios请求拦截器、响应拦截器中,分别应该设置什么,有什么作用?

2.1.请求拦截器实现示例

2.2.请求拦截器中设置什么?

2.2.1 统一身份验证(token)

2.2.2 设置请求头

2.2.3 加密请求体数据

2.2.4 return Promise.reject(error); 是什么?

2.2.4.1. Promise.reject(error) 的作用

2.2.4.2. 在 Axios 拦截器中的用途

2.2.4.3 具体场景示例

2.3.响应拦截器中设置什么?

2.3.1 成功响应处理(response 回调)

2.3.2  GET 请求缓存

2.3.3  判断并处理 Blob 响应(跳过处理)

2.3.4 错误响应处理(error 回调)

2.4 移除拦截器

三、拦截器集成应用

 3.1多环境配置

1. 环境变量配置

2. 动态创建 Axios 实例

3. 请求拦截器(多环境逻辑)

4. 响应拦截器(多环境逻辑)

四、Axios请求拦截器、响应拦截器的执行顺序

4.1 请求拦截器

4.2 响应拦截器

五、Axios 请求拦截器和响应拦截器的完整流程图表展示

5.1 请求拦截器成功流程

5.2 请求拦截器报错流程

5.3 响应拦截器成功流程

5.4 响应拦截器报错流程

5.5 总表

六、总结


前言

在现代 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) 的主要目的是:

  1. 让错误继续传递:如果不 reject,错误会被拦截器“吞掉”,外层 axios.get().catch() 无法捕获。

  2. 统一错误处理:可以在拦截器里先处理错误(如 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处理 )


网站公告

今日签到

点亮在社区的每一天
去签到