Axios 封装的作用
文章类型:Vue
发布者:hp
发布时间:2026-07-06
在实际项目开发中,直接使用 axios 会导致大量重复代码和分散的配置。通过二次封装,可以统一管理请求配置、错误处理、权限验证等通用逻辑,大幅提升开发效率和代码质量。
首先创建一个配置好的 axios 实例,统一管理基础配置:
// utils/request.js
import axios from 'axios'
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // 统一的基础URL
timeout: 15000, // 请求超时时间
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
})在请求发送前进行统一处理,如添加 token、参数处理等:
service.interceptors.request.use(
config => {
// 1. 添加 token
const token = localStorage.getItem('token')
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
// 2. 添加时间戳防止缓存
if (config.method === 'get') {
config.params = {
...config.params,
_t: Date.now()
}
}
// 3. 显示 loading(可选)
// showLoading()
return config
},
error => {
console.error('请求错误:', error)
return Promise.reject(error)
}
)统一处理响应数据和错误:
service.interceptors.response.use(
response => {
// hideLoading()
const res = response.data
// 根据后端返回的 code 判断
if (res.code !== 200) {
// 处理业务错误
if (res.code === 401) {
// token 过期,跳转登录
localStorage.removeItem('token')
router.push('/login')
}
// 错误提示
Message.error(res.message || '请求失败')
return Promise.reject(new Error(res.message || 'Error'))
}
return res.data // 只返回数据部分
},
error => {
// hideLoading()
// 处理 HTTP 错误
let message = '网络错误'
if (error.response) {
switch (error.response.status) {
case 400:
message = '请求参数错误'
break
case 401:
message = '未授权,请重新登录'
localStorage.removeItem('token')
router.push('/login')
break
case 403:
message = '拒绝访问'
break
case 404:
message = '请求地址不存在'
break
case 500:
message = '服务器错误'
break
case 502:
message = '网关错误'
break
case 503:
message = '服务不可用'
break
case 504:
message = '网关超时'
break
default:
message = `连接错误${error.response.status}`
}
} else if (error.message.includes('timeout')) {
message = '请求超时'
} else if (error.message.includes('Network Error')) {
message = '网络连接异常'
}
Message.error(message)
return Promise.reject(error)
}
)
export default service统一的 baseURL、超时时间、请求头设置,避免分散配置
自动添加 token,token 过期自动跳转登录,无需手动处理
集中处理 HTTP 状态码错误,统一错误提示
统一处理返回数据格式,只返回需要的数据部分
自动显示/隐藏 loading,避免重复的控制代码
可配置请求失败自动重试机制
将不同业务的 API 分模块管理,保持代码清晰:
// api/user.js
import request from '@/utils/request'
// 登录
export function login(data) {
return request({
url: '/user/login',
method: 'post',
data
})
}
// 获取用户信息
export function getUserInfo() {
return request({
url: '/user/info',
method: 'get'
})
}
// 更新用户信息
export function updateUserInfo(data) {
return request({
url: '/user/update',
method: 'put',
data
})
}使用示例:
import { login, getUserInfo } from '@/api/user'
export default {
data() {
return {
userInfo: null
}
},
async mounted() {
try {
// 直接调用,无需关心 token、错误处理等
const data = await getUserInfo()
this.userInfo = data
} catch (error) {
// 错误已经在拦截器中处理
// 这里可以做额外的业务处理
}
},
methods: {
async handleLogin() {
try {
const res = await login({
username: this.username,
password: this.password
})
localStorage.setItem('token', res.token)
this.$router.push('/home')
} catch (error) {
// 已统一处理
}
}
}
}// 防止重复请求
const pending = new Map()
const addPending = (config) => {
const url = [config.method, config.url].join('&')
config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => {
if (!pending.has(url)) {
pending.set(url, cancel)
}
})
}
const removePending = (config) => {
const url = [config.method, config.url].join('&')
if (pending.has(url)) {
const cancel = pending.get(url)
cancel(url)
pending.delete(url)
}
}
// 在请求拦截器中使用
service.interceptors.request.use(config => {
removePending(config) // 检查是否存在重复请求
addPending(config) // 添加当前请求到 pending
return config
})// 在响应拦截器的错误处理中添加重试
service.interceptors.response.use(
response => response,
error => {
const config = error.config
// 如果没有配置重试或已达到最大重试次数
if (!config || !config.retry) {
return Promise.reject(error)
}
// 设置重试计数
config.__retryCount = config.__retryCount || 0
// 检查是否已达到最大重试次数
if (config.__retryCount >= config.retry) {
return Promise.reject(error)
}
// 增加重试计数
config.__retryCount += 1
// 创建延迟重试的 Promise
const backoff = new Promise(resolve => {
setTimeout(() => {
resolve()
}, config.retryDelay || 1000)
})
// 返回重试的 Promise
return backoff.then(() => service(config))
}
)
// 使用时配置重试
request({
url: '/api/data',
method: 'get',
retry: 3, // 重试 3 次
retryDelay: 1000 // 每次重试延迟 1 秒
})// api/upload.js
import request from '@/utils/request'
export function uploadFile(file, onProgress) {
const formData = new FormData()
formData.append('file', file)
return request({
url: '/upload',
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
},
onUploadProgress: (progressEvent) => {
if (onProgress) {
const percent = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
)
onProgress(percent)
}
}
})
}src/
├── utils/
│ └── request.js # axios 封装
├── api/
│ ├── user.js # 用户相关 API
│ ├── article.js # 文章相关 API
│ ├── upload.js # 上传相关 API
│ └── index.js # API 统一导出
└── components/
└── YourComponent.vue # 使用 APIAxios 二次封装带来的核心价值:
暂无评论,快来发表第一条评论吧~