封装 axios
需要具备以下几个功能:
- 请求超时时间设置。
- 根据项目环境设置请求路径。
- 请求拦截器:自动添加
Token
。 - 响应拦截器:处理响应状态码或数据格式化。
- 请求队列实现
loading
效果。 - 取消请求功能:页面切换时取消未完成的请求。
下面是一个完整的 axios
封装示例,包含这些功能:
1. 安装依赖
npm install axios nprogress
nprogress
是一个用于显示加载进度条的库,可以帮助实现 loading
效果。
2. 封装 axios
js
// src/utils/request.js
import axios from 'axios';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
// 设置取消请求的 token
const CancelToken = axios.CancelToken;
let pendingRequests = new Map(); // 用于存储请求队列
// 添加请求到队列
const addRequestToQueue = (config) => {
const requestKey = `${config.method}:${config.url}`;
config.cancelToken = new CancelToken((cancel) => {
if (!pendingRequests.has(requestKey)) {
pendingRequests.set(requestKey, cancel);
}
});
};
// 移除队列中的请求
const removeRequestFromQueue = (config) => {
const requestKey = `${config.method}:${config.url}`;
if (pendingRequests.has(requestKey)) {
const cancel = pendingRequests.get(requestKey);
cancel(requestKey);
pendingRequests.delete(requestKey);
}
};
// 清空请求队列(用于页面切换时取消请求)
export const clearRequestQueue = () => {
pendingRequests.forEach((cancel, key) => {
cancel(key);
});
pendingRequests.clear();
};
// 根据环境变量设置基础URL
const baseURL = process.env.NODE_ENV === 'production' ? 'https://api.production.com' : 'https://api.development.com';
// 创建 axios 实例
const service = axios.create({
baseURL: baseURL,
timeout: 5000, // 超时时间
headers: {
'Content-Type': 'application/json',
}
});
// 请求拦截器
service.interceptors.request.use(
(config) => {
// 启动进度条
NProgress.start();
// 自动添加 Token 到请求头
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
// 添加请求到队列,防止重复请求
removeRequestFromQueue(config);
addRequestToQueue(config);
return config;
},
(error) => {
// 关闭进度条
NProgress.done();
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
(response) => {
// 关闭进度条
NProgress.done();
// 请求成功后移除队列中的该请求
removeRequestFromQueue(response.config);
const res = response.data;
// 自定义状态码处理
if (res.code !== 200) {
// 错误处理
console.error('Error:', res.message);
// 比如处理 token 过期
if (res.code === 401) {
console.error('Token expired, redirecting to login...');
// 可以执行登出操作,或跳转到登录页面
}
return Promise.reject(new Error(res.message || 'Error'));
} else {
return res; // 返回处理过的数据
}
},
(error) => {
// 关闭进度条
NProgress.done();
// 请求失败时清除队列中的该请求
removeRequestFromQueue(error.config || {});
return Promise.reject(error);
}
);
export default service;
3. 使用导航守卫取消未完成请求
在页面切换时,通过 Vue Router 的导航守卫取消未完成的请求。
js
// src/router/index.js
import Vue from 'vue';
import Router from 'vue-router';
import { clearRequestQueue } from '@/utils/request'; // 引入清除请求队列的函数
Vue.use(Router);
const router = new Router({
routes: [
// 定义你的路由
]
});
router.beforeEach((to, from, next) => {
// 页面切换前取消所有未完成的请求
clearRequestQueue();
next();
});
export default router;
4. 在组件中使用 axios
封装
在 Vue 组件中使用封装的 axios
:
vue
<template>
<div>
<h1>{{ data }}</h1>
</div>
</template>
<script>
import service from '@/utils/request';
export default {
data() {
return {
data: null,
};
},
async created() {
try {
const response = await service.get('/some-endpoint');
this.data = response.data;
} catch (error) {
console.error('Error fetching data:', error);
}
}
};
</script>
5. 效果解析
- 请求超时 :在
axios
实例中通过timeout: 5000
设置了 5 秒的请求超时。 - 根据环境设置请求路径 :使用
process.env.NODE_ENV
判断当前环境,并设置baseURL
。 - 请求拦截:自动添加 Token :每次请求会从
localStorage
中获取Token
并添加到Authorization
请求头中。 - 响应拦截:处理状态码与格式化数据:统一处理了响应的状态码,如果不是 200,会抛出错误。
- 请求队列与
loading
效果 :使用nprogress
显示加载进度条,且通过请求队列管理,防止重复请求。 - 取消请求功能 :在每次请求时生成一个取消
token
,并在页面切换时通过导航守卫取消未完成的请求。
通过这种封装,你可以有效管理请求的全生命周期,并确保在项目中对 HTTP 请求的处理变得更高效、可维护。