JS Axios 封装最佳实践与实战指南
在现代前端开发中,Axios已成为处理HTTP请求的主流工具之一。但直接使用Axios可能面临配置分散、错误处理重复、环境适配复杂等问题。本文将从基础到进阶,详解如何封装Axios,提升项目的可维护性与扩展性。
一、Axios封装的核心价值
Axios本身是功能强大的HTTP客户端,但在复杂项目中,直接使用其默认API会导致以下问题:
- 不同接口的基础URL、超时时间、请求头等配置分散
- 错误处理逻辑重复书写
- 缺乏请求重试、取消等高级功能
- 难以适配开发/生产环境切换
封装的核心目标:通过统一配置、拦截器和功能扩展,实现请求逻辑的复用与标准化,让业务代码更简洁。
二、基础封装实现
1. 核心配置与拦截器
以下是最基础的Axios封装,包含默认配置、请求拦截、响应拦截和错误处理:
import axios from 'axios';
class AxiosService {
constructor(config = {}) {
// 1. 创建Axios实例,配置基础参数
this.instance = axios.create({
baseURL: config.baseURL || 'https://api.example.com',
timeout: config.timeout || 5000,
headers: {
'Content-Type': 'application/json',
...config.headers
}
});
// 2. 初始化拦截器
this.setupInterceptors();
}
// 2.1 请求拦截器:添加token、统一参数格式
setupInterceptors() {
this.instance.interceptors.request.use(
(config) => {
// 示例:从localStorage获取token
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
// 请求错误直接抛出
return Promise.reject(error);
}
);
// 2.2 响应拦截器:统一数据格式、错误分类
this.instance.interceptors.response.use(
(response) => {
// 假设接口返回格式为 { code, data, msg }
const { data } = response;
if (data.code === 200) {
return data.data; // 仅返回业务数据
} else {
console.error(`请求错误: ${data.msg}`);
return Promise.reject(new Error(data.msg));
}
},
(error) => {
const { response } = error;
if (!response) {
// 网络错误
return Promise.reject(new Error('网络连接失败,请检查网络设置'));
}
// 错误状态码分类处理
switch (response.status) {
case 401:
// Token过期,跳转登录页
localStorage.removeItem('token');
window.location.href = '/login';
break;
case 403:
return Promise.reject(new Error('权限不足'));
case 500:
return Promise.reject(new Error('服务器内部错误'));
default:
return Promise.reject(new Error(`请求错误: ${response.status}`));
}
}
);
}
// 3. 封装请求方法
get(url, params = {}) {
return this.instance.get(url, { params });
}
post(url, data = {}) {
return this.instance.post(url, data);
}
put(url, data = {}) {
return this.instance.put(url, data);
}
delete(url, params = {}) {
return this.instance.delete(url, { params });
}
}
export default AxiosService;
三、进阶功能扩展
1. 请求重试机制
针对5xx错误或网络波动,实现自动重试功能:
class AxiosService {
constructor(config = {}) {
this.instance = axios.create({...});
this.retryCount = config.retryCount || 3; // 重试次数
this.retryDelay = config.retryDelay || 1000; // 重试间隔(ms)
this.setupInterceptors();
}
setupInterceptors() {
this.instance.interceptors.response.use(
// ...基础拦截器逻辑
(error) => {
const { response, config } = error;
// 判断是否需要重试(5xx错误或网络错误)
if (this.shouldRetry(response, error) && this.retryCount > 0) {
this.retryCount--;
// 延迟后重试请求
return new Promise(resolve => {
setTimeout(() => {
resolve(this.instance(config));
}, this.retryDelay);
});
}
return Promise.reject(error);
}
);
}
shouldRetry(response, error) {
// 网络错误或5xx状态码触发重试
return !response ||
(response.status >= 500 && response.status < 600) ||
error.message.includes('NetworkError');
}
}
2. 取消请求功能
防止重复请求或组件卸载时残留请求:
class AxiosService {
constructor(config = {}) {
this.instance = axios.create({...});
this.cancelTokenMap = new Map(); // 存储取消令牌
this.setupInterceptors();
}
// 发起请求时生成取消令牌
get(url, params = {}, cancelKey = null) {
const controller = new AbortController();
const signal = controller.signal;
if (cancelKey) {
this.cancelTokenMap.set(cancelKey, controller);
}
return this.instance.get(url, { params, signal });
}
// 取消指定请求
cancelRequest(cancelKey) {
const controller = this.cancelTokenMap.get(cancelKey);
if (controller) {
controller.abort();
this.cancelTokenMap.delete(cancelKey);
}
}
// 组件卸载时取消所有请求
cancelAllRequests() {
this.cancelTokenMap.forEach(controller => controller.abort());
this.cancelTokenMap.clear();
}
}
3. 环境配置适配
区分开发/生产环境的API地址:
// 环境配置
const envConfig = {
development: {
baseURL: 'http://localhost:3000/api',
timeout: 5000
},
production: {
baseURL: 'https://api.example.com',
timeout: 10000
}
};
// 实例化时传入环境参数
const api = new AxiosService({
baseURL: envConfig[process.env.NODE_ENV || 'development'].baseURL,
timeout: envConfig[process.env.NODE_ENV || 'development'].timeout
});
四、实战应用场景
1. 在Vue项目中使用
// main.js
import Vue from 'vue';
import App from './App.vue';
import AxiosService from './axiosService';
// 实例化封装后的Axios
const api = new AxiosService({
baseURL: process.env.NODE_ENV === 'production'
? 'https://prod-api.com'
: 'https://dev-api.com'
});
// 挂载到Vue原型
Vue.prototype.$api = api;
new Vue({
render: h => h(App)
}).$mount('#app');
// 组件中使用
export default {
methods: {
async fetchUser() {
try {
const user = await this.$api.get('/user', { id: 1 });
this.userData = user;
} catch (err) {
console.error('获取用户失败', err);
}
}
}
};
2. 在React项目中使用
// useApi.js 自定义Hook
import { useState, useEffect } from 'react';
import AxiosService from './axiosService';
export function useApi() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const api = new AxiosService();
const request = async (method, url, params = {}) => {
setLoading(true);
try {
const result = await api[method](url, params);
setData(result);
return result;
文章版权声明:除非注明,否则均为Dark零点博客原创文章,转载或复制请以超链接形式并注明出处。

