【vue ajax】封装ajax,可直接复用
'# 【vue ajax】封装ajax,可直接复用
一、背景与问题
在Vue项目中,频繁的Ajax请求是常态。但原始的fetch或axios使用方式存在以下问题:
- 重复代码:每个接口都需要单独处理响应和错误
- 统一管理困难:不同接口的超时时间、请求头配置不一致
- 安全隐患:未统一处理token、CORS等安全问题
- 性能瓶颈:未进行请求缓存和压缩优化
传统做法是直接在组件中使用axios.get()/axios.post(),但随着项目规模扩大,这种做法会导致代码冗余、可维护性差。我们需要通过封装构建一个可复用的Ajax工具,解决上述问题。
二、基本原理
Vue项目中Ajax封装的核心原理是:
- 创建Axios实例并配置默认参数
- 添加请求和响应拦截器
- 统一处理错误、token、超时等配置
- 提供封装后的API供组件调用
关键设计点包括:
- 请求缓存机制
- 超时自动重试
- 响应数据格式统一
- 错误码分类处理
- 接口日志记录
三、环境准备
npm install axios项目结构建议:
src/
├── utils/
│ └── ajax.js
├── components/
│ └── Login.vue
└── App.vue四、核心实现
1. 创建Axios实例并配置
// src/utils/ajax.js
import axios from 'axios';
// 创建Axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL, // 从环境变量获取基础URL
timeout: 10000, // 默认超时时间
headers: {
'Content-Type': 'application/json'
}
});关键点:
- 使用环境变量配置基础URL
- 设置统一的Content-Type
- 超时时间应根据接口特性动态调整
2. 添加请求拦截器
// 请求拦截器
service.interceptors.request.use(
config => {
// 1. 添加token
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
// 2. 添加请求时间戳
config.headers['X-Request-Time'] = Date.now();
// 3. 缓存请求参数
const cacheKey = `${config.method}-${config.url}`;
if (config.cache && !cacheKey) {
localStorage.setItem(cacheKey, JSON.stringify(config.data));
}
return config;
},
error => {
// 请求拦截错误处理
return Promise.reject(error);
}
);3. 添加响应拦截器
// 响应拦截器
service.interceptors.response.use(
response => {
// 1. 响应数据格式统一
const { data } = response;
if (data.code === 200) {
return data.data;
}
// 2. 错误码处理
switch (data.code) {
case 401:
// 未授权处理
localStorage.removeItem('token');
window.location.reload();
break;
case 500:
console.error('服务器内部错误');
break;
default:
console.error('未知错误', data.message);
}
return Promise.reject(data);
},
error => {
// 2. 响应错误处理
if (error.response) {
// 响应状态码处理
switch (error.response.status) {
case 404:
console.error('接口未找到');
break;
case 500:
console.error('服务器内部错误');
break;
}
} else if (error.request) {
// 网络错误处理
console.error('网络请求失败:', error.message);
} else {
console.error('请求配置错误:', error.message);
}
return Promise.reject(error);
}
);五、完整案例
1. 登录接口封装
// src/utils/ajax.js
export function login(username, password) {
return service.post('/api/login', {
username,
password
});
}2. 登录组件实现
<template>
<div>
<input v-model="username" placeholder="用户名" />
<input v-model="password" type="password" placeholder="密码" />
<button @click="handleLogin">登录</button>
<p v-if="error" class="error">{{ error }}</p>
</div>
</template>
<script>
import { login } from '@/utils/ajax';
export default {
data() {
return {
username: '',
password: '',
error: ''
};
},
methods: {
async handleLogin() {
try {
const result = await login(this.username, this.password);
console.log('登录成功:', result);
this.$router.push('/dashboard');
} catch (err) {
this.error = err.message || '登录失败';
}
}
}
};
</script>3. 接口响应示例
{
"code": 200,
"message": "成功",
"data": {
"token": "abc123xyz"
}
}六、源码解析
1. 请求拦截器逻辑
- token注入:在请求头添加Authorization字段,实现身份验证
- 请求缓存:通过localStorage缓存请求参数,避免重复请求
- 时间戳添加:用于防重放攻击
2. 响应拦截器逻辑
- 数据格式统一:将后端返回的
{code, message, data}统一转换为data字段 - 错误码处理:根据不同的错误码执行不同的处理逻辑
- 网络错误处理:区分不同类型的错误(如网络中断、接口未找到等)
七、进阶使用
1. 请求重试机制
service.interceptors.request.use(config => {
// 添加重试逻辑
config.retries = 3;
config.retry = 0;
return new Promise((resolve, reject) => {
const retry = () => {
if (config.retry < config.retries) {
config.retry++;
service(config).then(resolve).catch(retry);
} else {
reject(new Error('请求重试失败'));
}
};
retry();
});
});2. 接口日志记录
service.interceptors.request.use(config => {
console.log(`[请求日志] ${config.method} ${config.url}`);
return config;
});
service.interceptors.response.use(response => {
console.log(`[响应日志] ${response.config.method} ${response.config.url}`);
return response;
});3. 请求压缩
service.interceptors.request.use(config => {
if (config.data && typeof config.data === 'object') {
config.data = JSON.stringify(config.data);
}
return config;
});八、性能与工程实践
1. 性能优化
- 请求缓存:对重复请求进行缓存,避免重复发送
- 压缩数据:对请求参数进行压缩,减少传输体积
- 超时控制:根据接口特性设置合理的超时时间
- 连接复用:使用HTTP/2实现连接复用
2. 安全风险
- CSRF防护:添加XSRF-TOKEN头,配合服务器验证
- 数据验证:对返回数据进行校验,防止数据篡改
- 敏感信息过滤:避免将敏感信息暴露在日志中
- 限制频率:通过请求头限制请求频率,防止暴力破解
3. 异常处理
- 网络错误:处理网络中断、DNS解析失败等
- 服务器错误:处理500系列错误码
- 客户端错误:处理400系列错误码
九、常见问题与踩坑
1. 常见错误
错误示例:
// 错误:未处理错误
service.post('/api/login', { username, password });问题分析:
- 未处理错误时,页面可能出现未处理的Promise
- 可能导致页面崩溃或数据不一致
解决方法:
try {
const result = await service.post('/api/login', { username, password });
} catch (err) {
console.error('登录失败:', err.message);
}2. 常见坑点
坑点1:未处理跨域问题
- 解决方案:配置代理服务器,或使用CORS头
坑点2:未处理token过期
- 解决方案:在响应拦截器中检测401错误,自动刷新token
坑点3:未处理请求参数类型错误
- 解决方案:在请求拦截器中进行类型校验
十、最佳实践
- 统一接口:所有接口统一使用
/api/前缀 - 环境区分:区分开发、测试、生产环境的API地址
- 错误分级:按错误严重程度分级处理(如致命错误、警告)
- 日志分级:按日志级别记录不同类型的日志
- 版本控制:对API进行版本控制,避免接口变更影响现有功能
十一、总结
通过封装Ajax请求,我们实现了以下目标:
- 统一了请求和响应处理逻辑
- 提升了代码复用性
- 强化了安全防护
- 优化了性能表现
- 提高了可维护性
在实际开发中,应根据项目需求选择合适的封装方案。对于大型项目,建议使用axios的完整封装;对于小型项目,可以使用fetch的简单封装。需要注意的是,过度封装可能导致代码复杂度增加,因此要根据项目规模合理选择。
性能优化方面,建议结合请求缓存、数据压缩、连接复用等技术,同时注意安全防护,避免敏感信息泄露。在遇到错误时,要区分不同类型的错误,采取针对性的处理策略。通过合理的封装和实践,可以显著提升Vue项目的开发效率和系统稳定性。
评论已关闭