一、完整封装方案
1. 基础封装(request.js)
// src/utils/request.js
import axios from 'axios'
import { ElMessage } from 'element-plus' // 按需引入UI框架提示组件
// 创建axios实例
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API, // 从环境变量读取API地址
timeout: 5000 // 请求超时时间
})
// 请求拦截器
service.interceptors.request.use(
config => {
// 在这里可以统一添加token等操作
const token = localStorage.getItem('token')
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data
// 这里根据后端返回的数据结构进行调整
if (res.code !== 200) {
ElMessage.error(res.message || 'Error')
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
},
error => {
// 处理HTTP错误状态码
let message = ''
if (error.response) {
switch (error.response.status) {
case 401:
message = '认证失败,请重新登录'
break
case 403:
message = '当前操作没有权限'
break
case 404:
message = '资源不存在'
break
case 500:
message = '服务器错误'
break
default:
message = error.message
}
}
ElMessage.error(message)
return Promise.reject(error)
}
)
// 封装通用请求方法
export function request(options) {
return service(options)
}
// 封装GET请求
export function get(url, params, options = {}) {
return service({
url,
method: 'get',
params,
...options
})
}
// 封装POST请求
export function post(url, data, options = {}) {
return service({
url,
method: 'post',
data,
...options
})
}
// 其他请求方法同理可以继续封装...
2. API 统一管理(api.js)
// src/api/index.js
import { get, post } from '@/utils/request'
// 示例:用户相关API
export const userApi = {
// 登录
login(data) {
return post('/api/user/login', data)
},
// 获取用户信息
getUserInfo() {
return get('/api/user/info')
},
// 修改用户信息
updateUser(data) {
return post('/api/user/update', data)
}
}
// 示例:商品相关API
export const productApi = {
// 获取商品列表
getList(params) {
return get('/api/product/list', params)
},
// 获取商品详情
getDetail(id) {
return get(`/api/product/detail/${id}`)
}
}
二、在组件中使用示例
<template>
<div>
<button @click="getUserData">获取用户信息</button>
<button @click="submitForm">提交表单</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { userApi } from '@/api'
// 获取用户信息示例
const getUserData = async () => {
try {
const res = await userApi.getUserInfo()
console.log('用户数据:', res.data)
} catch (error) {
console.error('获取用户信息失败:', error)
}
}
// 提交表单示例
const formData = ref({
username: '',
password: ''
})
const submitForm = async () => {
try {
const res = await userApi.login(formData.value)
console.log('登录成功:', res)
} catch (error) {
console.error('登录失败:', error)
}
}
</script>
三、拓展
1. 取消重复请求
// 在request.js中添加
const pendingMap = new Map()
const addPending = (config) => {
const key = `${config.url}&${config.method}`
const cancelToken = new axios.CancelToken(cancel => {
if (!pendingMap.has(key)) {
pendingMap.set(key, cancel)
}
})
config.cancelToken = cancelToken
}
const removePending = (config) => {
const key = `${config.url}&${config.method}`
if (pendingMap.has(key)) {
const cancel = pendingMap.get(key)
cancel(key)
pendingMap.delete(key)
}
}
// 在请求拦截器中添加
service.interceptors.request.use(config => {
removePending(config)
addPending(config)
// ...其他原有逻辑
})
// 在响应拦截器中添加
service.interceptors.response.use(response => {
removePending(response.config)
// ...其他原有逻辑
}, error => {
if (!axios.isCancel(error)) {
// ...其他原有错误处理
}
return Promise.reject(error)
})
2. 文件上传封装
// 在request.js中添加
export function uploadFile(url, file, options = {}) {
const formData = new FormData()
formData.append('file', file)
return service({
url,
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
},
...options
})
}
四、环境变量配置
在项目根目录创建 .env 文件:
# 开发环境
VITE_APP_BASE_API = '/dev-api'
# 生产环境
VITE_APP_BASE_API = '/prod-api'
五、TypeScript 支持(可选)
// src/types/api.d.ts
declare interface ResponseData<T = any> {
code: number
data: T
message: string
}
// 修改request.ts中的类型定义
export function get<T>(url: string, params?: any, options?: AxiosRequestConfig): Promise<ResponseData<T>>
export function post<T>(url: string, data?: any, options?: AxiosRequestConfig): Promise<ResponseData<T>>

被折叠的 条评论
为什么被折叠?



