创建一个二次封装的 Axios 库,该库能够自动处理 Token 刷新逻辑,同时具备取消请求的功能,并能够根据不同环境配置基础 URL 和其他配置。以下是实现这一目标的具体步骤:
思路步骤
1. 创建Axios实例
-
目的:初始化Axios实例,并设置一些基本配置,如基础URL和超时时间。
-
实现:
- 导入axios库。
- 使用
axios.create()方法创建一个新的Axios实例。 - 配置基础URL(通过环境变量动态设置)和请求超时时间。
- 导出创建的Axios实例。
2. 请求拦截器
-
目的:在请求被发送到服务器之前对请求进行预处理,例如添加认证Token到请求头部。
-
实现:
- 使用
axios.interceptors.request.use()方法添加请求拦截器。 - 拦截器函数接收配置对象作为参数。
- 从本地存储中获取认证Token。
- 如果存在Token,将其添加到请求头部的
Authorization字段中。 - 返回修改后的配置对象。
- 使用
3. 响应拦截器
-
目的:在响应到达客户端后对其进行处理,例如处理HTTP状态码、错误状态,并实现Token刷新逻辑。
-
实现:
- 使用
axios.interceptors.response.use()方法添加响应拦截器。 - 拦截器函数接收响应对象作为参数。
- 检查响应的状态码。
- 对于特定的状态码(如401),触发Token刷新流程。
- 对于其他状态码,输出相应的错误信息。
- 返回处理后的响应对象或者抛出错误。
- 使用
4. Token刷新机制
-
目的:当遇到401状态码时,自动刷新Token并重新发起请求。
-
实现:
- 定义一个
refreshToken函数,用于处理Token刷新过程。 - 使用
axios.post()向服务器发送刷新Token的请求。 - 成功刷新Token后,更新本地存储的Token和请求头部中的Token。
- 如果有正在刷新Token的请求正在进行,则等待该请求完成。
- 在响应拦截器中,当遇到401状态码时,调用
refreshToken函数,并重新发送原始请求。
- 定义一个
5. 取消重复请求
-
目的:实现一个机制来管理正在进行的请求,并在发起相同请求时取消旧的请求。
-
实现:
- 使用
Map来存储每个请求的取消源。 - 定义
cancelRequest函数,用于取消指定的请求。 - 定义
createCancelToken函数,用于创建新的取消请求源。 - 在请求拦截器中,为每个请求创建一个取消令牌。
- 在响应拦截器中,检查请求是否被取消,并相应地处理。
- 使用
6. 超时重发
-
目的:处理网络不稳定的情况,使用axios-retry插件实现自动重发。
-
实现:
- 导入
axios-retry插件。 - 使用
axios-retry(axios)函数启用重试功能。 - 配置重试次数和递增延迟时间。
- 导入
7. 统一错误处理
-
目的:创建一个统一的错误处理函数,用于处理所有API请求中的错误。
-
实现:
- 定义一个
handleError函数,用于处理错误。 - 在请求失败时调用
handleError函数。 - 输出错误信息,并返回一个被拒绝的Promise。
- 定义一个
8. 提供便捷的API请求函数
-
目的:提供一些便捷的方法来快速发起GET、POST等类型的请求。
-
实现:
- 定义一个通用的
request函数,用于处理各种HTTP方法。 - 根据传入的HTTP方法名调用相应的axios方法。
- 捕获错误并调用
handleError函数。 - 导出具体的方法如
get、post等。
- 定义一个通用的
9. 环境变量配置
-
目的:根据不同的部署环境动态配置基础URL和其他配置。
-
实现:
- 在环境变量配置文件中设置基础URL。
- 根据
process.env.NODE_ENV值确定当前环境。 - 设置
VUE_APP_API_BASE_URL环境变量,其值根据当前环境而定。
10. 导出封装后的Axios实例
-
目的:导出封装后的Axios实例,以便在其他模块中使用。
-
实现:
- 导出创建的Axios实例。
使用示例 (MyComponent.vue)
-
目的:在Vue组件中使用封装好的请求方法,并在组件销毁时取消所有未完成的请求。
-
实现:
- 在Vue组件中导入封装好的请求方法。
- 使用这些方法发起请求。
- 在
beforeDestroy生命周期钩子中取消所有未完成的请求。
总结
通过以上步骤,我们创建了一个封装良好的Axios库,它具有以下特点:
- 自动处理Token刷新:当遇到401状态码时自动刷新Token,并重新发起请求。
- 取消重复请求:实现了取消重复请求的机制,避免不必要的网络请求。
- 超时重发:使用axios-retry插件处理网络不稳定的情况,实现自动重发功能。
- 环境变量配置:根据不同的部署环境动态配置基础URL和其他配置。
- 统一错误处理:创建了统一的错误处理函数,确保错误处理的一致性。
- 便捷的API请求函数:提供了便捷的方法来快速发起各种HTTP请求。
- 取消未完成的请求:在Vue组件中可以方便地取消未完成的请求
代码实现
1. 创建 Axios 实例
目的: 创建一个 Axios 实例,并设置基础配置。 实现:
import axios from 'axios';
const instance = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL, // 动态配置基础 URL
timeout: 5000, // 设置请求超时时间为 5 秒
});
export default instance;
2. 请求拦截器
目的: 在请求发送前添加认证 Token 到请求头部。
实现:
import axios from './axios-instance';
// 请求拦截器
axios.interceptors.request.use(
(config) => {
const token = localStorage.getItem('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
3. 响应拦截器
目的: 处理响应状态码,实现 Token 刷新逻辑。
实现:
// 响应拦截器
axios.interceptors.response.use(
(response) => {
return response.data;
},
(error) => {
if (error.response) {
switch (error.response.status) {
case 401:
// Token 过期,需要刷新 Token
return refreshToken().then(() => {
// 重新发送请求
return axios(error.config);
}).catch(() => {
// Token 刷新失败
return Promise.reject(error);
});
case 403:
console.error('Forbidden:', error.response.data);
break;
case 404:
console.error('Not Found:', error.response.data);
break;
case 500:
console.error('Server Error:', error.response.data);
break;
default:
console.error('Other Error:', error.response.data);
break;
}
}
return Promise.reject(error);
}
);
4. Token 刷新机制
目的: 当遇到 401 状态码时,自动刷新 Token 并重新发起请求
实现:
// 存储刷新 Token 的请求
let refreshRequest;
/**
* 刷新 Token 的函数
* @returns {Promise}
*/
async function refreshToken() {
// 如果已经有刷新 Token 的请求正在进行,则等待该请求完成
if (refreshRequest) {
return refreshRequest;
}
// 开始刷新 Token 的请求
refreshRequest = axios.post('/auth/refresh-token').then((response) => {
// 更新本地存储的 Token
localStorage.setItem('token', response.data.token);
// 更新请求头部中的 Token
axios.defaults.headers.common['Authorization'] = `Bearer ${response.data.token}`;
return response.data.token;
}).finally(() => {
// 清除刷新 Token 的请求
refreshRequest = null;
});
return refreshRequest;
}
export default refreshToken;
5. 取消重复请求
目的: 实现机制来管理正在进行的请求,并在发起相同请求时取消旧的请求。
实现:
import axios from './axios-instance';
import CancelToken from 'axios/lib/cancel/CancelToken';
import isCancel from 'axios/lib/cancel/isCancel';
// 用于存储需要取消的请求
const cancelTokens = new Map();
/**
* 取消指定请求
* @param {String} requestName - 请求名称
*/
function cancelRequest(requestName) {
if (cancelTokens.has(requestName)) {
const source = cancelTokens.get(requestName);
if (!source.cancelled) {
source.cancel('取消请求');
}
cancelTokens.delete(requestName);
}
}
/**
* 创建取消请求源
* @param {String} requestName - 请求名称
* @returns {Object} - 取消请求源
*/
function createCancelToken(requestName) {
const source = CancelToken.source();
cancelTokens.set(requestName, source);
return source;
}
// 更新请求配置以包含取消令牌
axios.interceptors.request.use(
(config) => {
config.cancelToken = createCancelToken(config.url);
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 在响应拦截器中检查取消的请求
axios.interceptors.response.use(
(response) => {
return response;
},
(error) => {
if (axios.isCancel(error)) {
console.log('Request cancelled', error.message);
return Promise.reject(error);
}
return Promise.reject(error);
}
);
// 添加取消请求的方法
axios.cancelRequest = cancelRequest;
export default axios;
6. 超时重发
目的: 处理网络不稳定的情况,使用 axios-retry 插件实现自动重发。
实现:
import { retry } from 'axios-retry';
retry(axios, {
retries: 3, // 重试次数
retryDelay: (retryCount) => {
return retryCount * 1000; // 递增延迟时间
},
});
7. 统一错误处理
目的: 创建一个统一的错误处理函数,处理所有 API 请求中的错误。
实现:
/**
* 统一错误处理函数
* @param {Object} error - 错误对象
*/
function handleError(error) {
console.error('Error:', error);
return Promise.reject(error);
}
8. 提供便捷的 API 请求函数
目的: 提供一些便捷的方法来快速发起 GET、POST 等类型的请求。
实现:
/**
* 封装请求函数
* @param {String} method - HTTP 方法名
* @param {String} url - 请求 URL
* @param {Object} [data={}] - 请求体数据
* @param {Object} [config={}] - 请求配置
* @returns {Promise}
*/
async function request(method, url, data = {}, config = {}) {
try {
const response = await axios[method](url, data, config);
return response;
} catch (error) {
return handleError(error);
}
}
// 导出具体的方法
export const get = (url, config) => request('get', url, {}, config);
export const post = (url, data, config) => request('post', url, data, config);
export const put = (url, data, config) => request('put', url, data, config);
export const del = (url, data, config) => request('delete', url, data, config);
9. 环境变量配置 (environment.js)
目的: 根据不同的部署环境动态配置基础 URL 和其他配置。
实现:
// 设置环境变量
if (process.env.NODE_ENV === 'development') {
process.env.VUE_APP_API_BASE_URL = 'http://localhost:3000/api';
} else if (process.env.NODE_ENV === 'production') {
process.env.VUE_APP_API_BASE_URL = 'https://api.example.com';
}
10. 导出封装后的 Axios 实例
-
目的:导出封装后的 Axios 实例,以便在其他模块中使用。
-
实现:
1export default axios;
使用示例 (MyComponent.vue)
- 目的:在 Vue 组件中使用封装好的请求方法,并在组件销毁时取消所有未完成的请求。
export default axios;
- 目的: 在 Vue 组件中使用封装好的请求方法,并在组件销毁时取消所有未完成的请求。
实现:
<template>
<div>
<button @click="fetchData">Fetch Data</button>
<ul>
<li v-for="(item, index) in items" :key="index">
{{ item.title }}
</li>
</ul>
</div>
</template>
<script>
import { get } from '@/services/request-helper';
import axios from '@/services/axios-instance';
export default {
data() {
return {
items: [],
};
},
methods: {
async fetchData() {
try {
const data = await get('/items');
this.items = data;
} catch (error) {
console.error('Failed to fetch data:', error);
}
},
},
beforeDestroy() {
// 当组件销毁时取消所有未完成的请求
axios.cancelRequest('/items');
},
};
</script>
代码解释
-
创建 Axios 实例:
- 设置基础 URL:通过环境变量动态设置基础 URL,这样可以根据不同的部署环境来调整。
- 设置超时时间:设置了请求超时时间为 5 秒,这有助于提高用户体验,在长时间等待无响应的情况下给出反馈。
-
请求拦截器:
- 添加认证 Token:在请求发送前,从本地存储中获取认证 Token,并将其添加到请求头部。
-
响应拦截器:
- 处理不同状态码:针对不同的 HTTP 状态码进行相应的处理。
- 实现 Token 刷新:当遇到 401 状态码时,自动刷新 Token 并重新发起请求。
-
Token 刷新机制:
- 刷新 Token:定义了一个
refreshToken函数,用于刷新 Token。该函数确保同一时间内只有一个 Token 刷新请求正在进行。 - 更新 Token:成功刷新后更新本地存储的 Token 和请求头部中的 Token。
- 刷新 Token:定义了一个
-
取消重复请求:
- 管理取消请求:使用
Map来存储需要取消的请求,每个请求都有一个对应的取消源。 - 取消指定请求:提供了
cancelRequest方法来取消指定的请求。 - 请求配置中包含取消令牌:在请求配置中添加取消令牌,这样可以在需要的时候取消请求。
- 管理取消请求:使用
-
超时重发:
- 使用 axios-retry 插件:通过
axios-retry插件实现请求的自动重发功能,这对于处理网络不稳定的情况非常有用。
- 使用 axios-retry 插件:通过
-
统一错误处理:
- 错误处理函数:定义了一个
handleError函数,用于统一处理所有 API 请求中的错误。
- 错误处理函数:定义了一个
-
提供便捷的 API 请求函数:
- 封装请求函数:定义了一个通用的请求函数,可以处理 GET、POST、PUT 和 DELETE 请求。
- 导出具体方法:提供了具体的请求方法,如
get、post等,便于在应用中直接使用。
-
环境变量配置:
- 动态配置基础 URL:根据当前环境设置基础 URL。
-
使用示例 (
MyComponent.vue) :
- Vue 组件:在 Vue 组件中使用封装好的请求方法,并在组件销毁时取消所有未完成的请求。