1. 主文件 index.js
在主文件中,我们创建了一个 axios 实例,并设置了请求和响应拦截器。以下是如何在项目中进行配置和初始化 axios:
import axios from 'axios';
import qs from 'qs';
import addReqInterceptor from './reqInterceptor';
import addResInterceptor from './resInterceptor';
// 创建 axios 实例
const instance = axios.create({
baseURL: process.env.$baseUrl, // 在环境变量中设置基础的请求 URL
timeout: 1000 * 60, // 设置请求超时时间,单位是毫秒
withCredentials: true, // 跨域请求时是否需要携带 cookie
paramsSerializer: function (params) {
// 使用 qs 库对请求参数进行序列化,支持数组格式化
return qs.stringify(params, { arrayFormat: 'indices' });
},
});
// 添加请求拦截器
addReqInterceptor(instance);
// 添加响应拦截器
addResInterceptor(instance);
export default instance;
1.1 paramsSerializer
在 Axios
配置中,支持使用 params
对象作为参数。
当发起 GET
请求时,我可以设置 params
信息并且传递给 Axios
,Axios 会根据 paramsSerializer
自动将其序列化并附加到 URL 中。
2. 请求拦截器 reqInterceptor.js
在请求拦截器中,主要的工作是:
- 添加 Token:从存储中获取 Token 并将其放入请求头中。
- 取消请求功能:如果请求需要取消,则为其添加取消令牌。
import { getToken } from "./auth"; // 假设有一个获取 token 的方法
import axios from "axios";
// 请求拦截器
export default function addReqInterceptor(axiosInstance) {
axiosInstance.interceptors.request.use(
(options) => {
// 在 header 上携带 token
addRequestToken(options);
// 添加取消请求的配置项
addCancelToken(options);
return options;
},
(error) => {
// 请求错误的处理
console.warn(`Request interceptor error: ${error}`);
return Promise.reject(error);
}
);
}
// 添加 Token 到请求头
function addRequestToken(options) {
let tokenMsg = getToken(); // 获取 token
if (tokenMsg) {
tokenMsg = JSON.parse(tokenMsg);
if (tokenMsg.token && tokenMsg.token !== "undefined") {
// 将 token 放到请求头
options.headers.token = tokenMsg.token;
}
}
}
// 取消请求
const source = {}; // 用于存储取消的请求
function addCancelToken(options) {
const url = options.url; // 请求地址
if (options.useCancel) {
// 如果需要取消请求
if (source[url]) {
source[url].cancel(); // 取消之前的请求
}
// 获取一个CancelToken对象
const CancelToken = axios.CancelToken;
// source()将返回一个能取消请求的方法
source[url] = CancelToken.source();
options.cancelToken = source[url].token;
}
}
2.1 携带 Token
很多 API 接口
只允许经过身份验证的用户访问。如果没有携带 Token
或 Token
无效,服务器会返回 401
错误,表示用户需要重新认证。在请求拦截器中默认添加,可减少每次添加Token的麻烦
2.2 取消请求场景
用户切换组件或表格:
如果前一个请求尚未完成,而用户已经切换了组件或者表格,之前调用的相同的请求不再需要。如果仍然继续执行请求,则浪费了带宽和处理资源。
搜索输入时:
在搜索功能中,用户输入时会触发自动搜索请求。如果用户连续输入或者输入过快,每个输入都会发出新的请求,前一个请求可以取消
3. 响应拦截器 resInterceptor.js
在响应拦截器中,主要工作是:
- 检查 HTTP 状态码:如果状态码不在 2xx 范围内,请求出错需要抛出错误。
- 检查返回的 code 字段:根据后端定义的返回代码处理不同的业务逻辑(如 token 过期、操作失败等)。
// 响应拦截器
export default function addResInterceptor(axiosInstance) {
// 响应状态检查
axiosInstance.interceptors.response.use(checkStatus, (error) => {
return Promise.reject(error);
});
// 响应代码检查
axiosInstance.interceptors.response.use(checkCodes, (error) => {
return Promise.reject(error);
});
}
// 响应状态检查
function checkStatus(response) {
// 判断 HTTP 响应状态是否在 200~299 范围内
if (response.status >= 200 && response.status < 300) {
return response;
}
// 如果不在范围内,抛出错误
const errorText = codeMessage[response.status] || response.statusText;
const error = new Error(errorText);
error.name = response.status;
error.response = response;
throw error;
}
// 响应代码检查
function checkCodes(response) {
const data = response.data;
// 根据不同的 code 执行不同的操作
if (data.code === 10002 || data.code === 10004) {
// 如果 code 为 10002 或 10004,表示登录失效,弹出重新登陆操作
reLogIn();
} else if (data.code === -1) {
// 如果 code 为 -1,表示操作失败,弹出提示
// alert可以是内部项目封装的弹窗提示
alert({
text: data.message,
icon: "info",
button: "close",
});
}
return response; // 返回原始响应数据
}
// 服务器返回的状态信息
const codeMessage = {
200: "服务器成功返回请求的数据",
201: "新建或修改数据成功",
202: "一个请求已经进入后台排队(异步任务)中",
204: "删除数据成功",
400: "发出的请求有错误,服务器没有进行新建或修改数据的操作",
401: "用户没有权限(令牌、用户名、密码错误)",
403: "用户得到授权,但是访问是被禁止的",
404: "发出的请求针对的是不存在的记录,服务器没有进行操作",
406: "请求的格式不可得",
410: "请求的资源被永久删除,且不会再得到",
422: "当创建一个对象时,发生一个验证错误",
500: "服务器发生错误,请检查服务器",
502: "网关错误",
503: "服务不可用,服务器暂时过载或维护",
504: "网关超时",
};
在请求和响应拦截器中,我省略了部分项目业务独有的代码判断。您可以在对应的代码中加上你项目中独有的一些判断和修改传参,
4.封装get和post请求
axios
返回的结果里不只是后端的结果信息,还有 config
,headers
等信息。但是我们一般在开发中只需要其中的 data
信息。
axios
返回的结果如下:
为了减少每次请求都需要从 axios
返回的完整响应对象中提取 data
的操作,我们可以对 get
和 post
方法进行封装。
// 封装 GET 请求
export function get(url, options) {
return instance
.get(url, options)
.then(response => response.data) // 只返回 data 部分
.catch(error => {
console.error("请求 GET 错误:", error);
return Promise.reject(error); // 返回错误信息
});
}
// 封装 POST 请求
export function post(url, options) {
return instance
.post(url, options)
.then(response => response.data) // 只返回 data 部分
.catch(error => {
console.error("请求 POST 错误:", error);
return Promise.reject(error); // 返回错误信息
});
}
使用封装的 post
示例:
import { post } from './api';
const postData = {
title: 'New Post',
content: 'This is the content of the new post.',
};
post('/api/posts', postData)
.then(data => {
console.log('返回的数据:', data);
})
.catch(error => {
console.error('请求失败:', error);
});
总结:
- 请求拦截器:在请求发送之前,添加了 Token、默认头部、取消请求配置。
- 响应拦截器:检查 HTTP 状态码,并根据返回的
code
字段执行不同的业务操作,比如弹出提示或登出。 - 封装get和post请求: 请求成功后,直接返回
response.data
,减少冗余代码。
提示: 如果您想了解 axios
的核心代码实现,可以参考:轻松掌握axios核心源码