https://www.doubao.com/thread/w476d78a62be8a4ce
网络请求封装方案
在Vue项目中,我们通常使用axios作为HTTP客户端,并对其进行封装以简化请求流程、统一错误处理和请求拦截。以下是一个完整的网络请求封装方案:
1. 安装axios
npm install axios --save
2. 创建请求配置和封装
在src目录下创建utils/request.js文件,用于封装axios:
// src/utils/request.js
import axios from 'axios';
import { ElMessage } from 'element-plus';
// 创建axios实例
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API, // 从环境变量中获取API基础路径
timeout: 5000, // 请求超时时间
headers: {
'Content-Type': 'application/json;charset=utf-8',
},
});
// 请求拦截器
service.interceptors.request.use(
(config) => {
// 在发送请求之前做些什么
// 例如:添加token、设置请求头等
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
},
(error) => {
// 对请求错误做些什么
console.log(error);
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
(response) => {
// 对响应数据做些什么
const res = response.data;
// 根据业务需求判断响应状态
if (res.code !== 200) {
ElMessage({
message: res.message || 'Error',
type: 'error',
duration: 3000,
});
// 例如:401表示未登录,跳转到登录页
if (res.code === 401) {
// 跳转到登录页的逻辑
localStorage.removeItem('token');
window.location.href = '/login';
}
return Promise.reject(new Error(res.message || 'Error'));
} else {
return res;
}
},
(error) => {
// 对响应错误做些什么
console.log('err' + error); // for debug
let message = error.message;
if (error.response) {
// 根据不同的HTTP状态码返回不同的错误信息
const status = error.response.status;
message = `请求错误(${status})`;
switch (status) {
case 400:
message = '错误请求';
break;
case 401:
message = '未授权,请重新登录';
break;
case 403:
message = '拒绝访问';
break;
case 404:
message = '请求错误,未找到该资源';
break;
case 500:
message = '服务器端出错';
break;
default:
message = `连接错误(${status})`;
}
} else if (error.message.includes('timeout')) {
message = '请求超时';
} else {
message = '连接服务器失败';
}
ElMessage({
message: message,
type: 'error',
duration: 3000,
});
return Promise.reject(error);
}
);
// 封装常用的请求方法
export default {
get(url, params = {}) {
return service.get(url, { params });
},
post(url, data = {}) {
return service.post(url, data);
},
put(url, data = {}) {
return service.put(url, data);
},
delete(url, params = {}) {
return service.delete(url, { params });
},
};
3. 配置环境变量
在项目根目录创建.env.development和.env.production文件,分别配置开发和生产环境的API基础路径:
# .env.development
VITE_APP_BASE_API = 'http://localhost:3000/api'
# .env.production
VITE_APP_BASE_API = 'https://production-api.com/api'
4. 创建API模块
在src目录下创建api文件夹,用于组织各个模块的API请求:
// src/api/user.js
import request from '@/utils/request';
export function login(data) {
return request.post('/user/login', data);
}
export function getUserInfo() {
return request.get('/user/info');
}
export function logout() {
return request.post('/user/logout');
}
5. 在组件中使用API
<!-- src/views/Login.vue -->
<template>
<div class="login-container">
<el-form :model="loginForm" ref="loginRef" label-width="80px">
<el-form-item label="用户名">
<el-input v-model="loginForm.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="loginForm.password" type="password" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleLogin">登录</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { login } from '@/api/user';
const loginForm = ref({
username: '',
password: '',
});
const loginRef = ref(null);
const handleLogin = async () => {
try {
const { data } = await login(loginForm.value);
localStorage.setItem('token', data.token);
ElMessage.success('登录成功');
// 跳转到首页
} catch (error) {
console.error('登录失败', error);
}
};
</script>
封装特点和优势
1.统一错误处理:在拦截器中统一处理错误,避免在每个组件中重复编写错误处理代码
2.请求拦截:自动添加token等请求头信息
3.环境配置:区分开发环境和生产环境的API地址
4.模块化组织:按功能模块组织API请求,使代码结构更清晰
5.Promise风格:使用async/await语法,使异步请求更简洁
6.可扩展性:可以轻松添加更多功能,如请求重试、上传进度等
你可以根据实际项目需求进一步扩展这个封装,例如添加请求缓存、请求取消、上传下载等功能。