在 Vue3 项目开发中,前后端联调是核心环节之一,而 axios 作为最主流的 HTTP 客户端库,承担着前端与后端数据交互的重任。
很多新手在使用 axios 时,会遇到三个高频痛点:
- 每个请求都重复写基础配置(如 baseURL、请求头),代码冗余;
- 本地开发时浏览器跨域报错,无法访问后端接口;
- 接口报错、网络异常、登录失效时,没有统一的处理逻辑,用户体验差。
一、环境准备
首先确保你的项目是 Vue3 + Vite 版本(Vue3 CLI 项目仅跨域配置略有差异,核心逻辑通用)。
1.1 安装 axios
打开项目终端,执行安装命令(三选一即可):
bash
npm install axios
# 或 yarn add axios
# 或 pnpm add axios
二、核心:axios 全局封装(重点)
封装的核心目标:统一配置、统一拦截、统一处理,避免重复代码,提升维护性,后续所有接口都复用该封装实例。
2.1 创建封装文件
在项目 src 目录下新建 utils 文件夹,再创建 request.js 文件(固定路径:src/utils/request.js),专门用于封装 axios。
2.2 完整封装代码(可直接复制使用)
代码带详细注释,关键步骤标注,新手可快速理解:
javascript
// 1. 引入 axios(核心依赖)
import axios from 'axios'
// 可选:引入 Element Plus 消息提示(项目常用,无侵权,可替换为其他UI库)
import { ElMessage } from 'element-plus'
// 2. 创建 axios 实例(核心步骤)
const service = axios.create({
// 基础路径:后续请求会自动拼接在前面(用环境变量配置,灵活切换环境)
baseURL: import.meta.env.VITE_API_URL,
// 请求超时时间:10秒(避免请求一直挂起)
timeout: 10000,
// 默认请求头(适配 JSON 格式接口,无需手动添加)
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
// 3. 请求拦截器:发送请求前统一处理(比如携带Token)
service.interceptors.request.use(
(config) => {
// 场景1:自动携带 Token(登录后存储在 localStorage,按需修改存储方式)
const token = localStorage.getItem('token')
if (token) {
// 格式需和后端一致,一般是 Bearer + 空格 + Token
config.headers.Authorization = `Bearer ${token}`
}
// 场景2:可在这里添加请求加载动画(比如 Element Plus 的 ElLoading)
// ElLoading.service({ text: '加载中...' })
return config
},
(error) => {
// 请求发送失败处理(比如网络中断、请求参数错误)
console.error('请求拦截错误:', error)
return Promise.reject(error)
}
)
// 4. 响应拦截器:接口返回数据后统一处理(报错、数据过滤)
service.interceptors.response.use(
(response) => {
// 直接返回后端数据(简化取值,无需每次都写 response.data)
// 可根据后端返回格式调整,比如后端统一返回 { code: 200, data: {}, msg: '' },可在这里判断 code
// if (response.data.code !== 200) { ElMessage.error(response.data.msg); return Promise.reject() }
return response.data
},
(error) => {
// 统一报错处理:根据 HTTP 状态码判断异常类型(重点!)
const { response } = error
if (response) {
// 有响应:接口返回错误(HTTP状态码非200)
switch (response.status) {
// 401:未授权/登录失效(最常见场景)
case 401:
ElMessage.error('登录已失效,请重新登录')
// 清空本地存储(Token、用户信息等)
localStorage.clear()
// 路由跳转至登录页(需先引入路由实例,路径按需修改)
// import router from '../router'
// router.push('/login')
break
// 403:无权限(比如普通用户访问管理员接口)
case 403:
ElMessage.error('没有权限访问该接口')
break
// 404:接口不存在(路径写错、后端接口未部署)
case 404:
ElMessage.error('请求接口不存在,请检查接口路径')
break
// 500:服务器错误(后端代码报错、服务器宕机)
case 500:
ElMessage.error('服务器异常,请稍后重试')
break
// 其他错误(比如 400 参数错误)
default:
ElMessage.error(response.data?.msg || '请求失败,请稍后再试')
}
} else {
// 无响应:网络异常、服务器未启动、跨域配置错误
ElMessage.error('网络异常,请检查网络连接或服务器状态')
}
// 抛出错误,便于页面中额外处理(可选)
return Promise.reject(error)
}
)
// 5. 导出 axios 实例,供其他文件引入使用
export default service
2.3 封装核心说明(必看)
- baseURL:使用 Vite 环境变量配置,区分开发/生产环境,无需手动修改代码;
- 请求拦截器:自动携带 Token,无需每个请求手动添加,还可添加加载动画;
- 响应拦截器:统一处理 HTTP 状态码报错,无需每个接口单独写 try/catch;
- 错误提示:集成 Element Plus 消息提示,若未使用 Element Plus,可替换为原生 alert。
三、接口统一管理(推荐)
不建议在页面中直接写接口地址和请求逻辑,单独管理接口,便于后续维护(比如接口路径修改,只需改一处)。
3.1 创建接口文件
在 src 目录下新建 api 文件夹,按业务模块划分接口文件(比如用户相关、商品相关),这里以用户接口为例,创建 user.js(路径:src/api/user.js)。
3.2 接口代码示例(可直接复制)
javascript
// 引入封装好的 axios 实例(路径按需调整)
import request from '../utils/request'
// 1. 登录接口(POST 请求,参数为 JSON 格式)
export function login(data) {
return request({
url: '/user/login', // 接口路径(会拼接 baseURL)
method: 'post', // 请求方式
data // 请求参数(POST 用 data,GET 用 params)
})
}
// 2. 获取用户信息(GET 请求,参数为 URL 拼接)
export function getUserInfo(params) {
return request({
url: '/user/info',
method: 'get',
params // 比如 { id: 123 },会自动拼接为 /user/info?id=123
})
}
// 3. 上传文件接口(POST + FormData 格式,特殊场景)
export function uploadFile(formData) {
return request({
url: '/file/upload',
method: 'post',
// 上传文件需手动设置 Content-Type,覆盖默认的 JSON 格式
headers: { 'Content-Type': 'multipart/form-data' },
data: formData // FormData 实例,比如 new FormData()
})
}
四、页面中使用接口(实战演示)
在 Vue3 组件(Setup 语法)中,直接引入接口函数调用,简洁高效,结合 async/await 处理异步请求。
vue
<template>
<div class="login-page">
<button @click="handleLogin" class="login-btn">登录</button>
</div>
</template>
<script setup>
// 1. 引入需要的接口函数(路径按需调整)
import { login, getUserInfo } from '../api/user'
// 可选:引入 Element Plus 消息提示(优化用户体验)
import { ElMessage } from 'element-plus'
// 2. 登录按钮点击事件(异步函数)
const handleLogin = async () => {
try {
// 调用登录接口,传递参数(和后端接口参数一致)
const res = await login({ username: 'admin', password: '123456' })
console.log('登录成功:', res)
// 登录成功后,存储 Token 到 localStorage
localStorage.setItem('token', res.token)
// 调用获取用户信息接口(登录后才能访问,需携带 Token)
const userInfo = await getUserInfo()
console.log('用户信息:', userInfo)
// 登录成功提示
ElMessage.success('登录成功!')
} catch (error) {
// 拦截器已统一报错,这里可处理额外逻辑(比如关闭加载动画)
console.log('请求失败:', error)
}
}
</script>
<style scoped>
.login-btn {
padding: 8px 16px;
cursor: pointer;
}
</style>
五、解决前端跨域问题(高频痛点)
5.1 什么是跨域?
浏览器同源策略限制:协议、域名、端口 任意一个不同,就会触发跨域,导致接口请求失败(控制台报错:Access to XMLHttpRequest at ... from origin ... has been blocked by CORS policy)。
示例:前端(http://localhost:3000)访问后端(http://localhost:8080),端口不同,触发跨域。
5.2 Vite 项目配置跨域(开发环境,重点)
开发环境下,通过 Vite 代理解决跨域,修改项目根目录的 vite.config.js 文件,添加 proxy 配置:
javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()], // Vite 基础插件(Vue3 必选)
// 跨域代理配置(核心)
server: {
port: 3000, // 前端启动端口(可自行修改)
proxy: {
// 匹配以 /api 开头的所有请求(和环境变量 VITE_API_URL 对应)
'/api': {
target: 'http://localhost:8080', // 后端真实接口地址(替换为你的后端地址)
changeOrigin: true, // 允许跨域(关键配置)
rewrite: (path) => path.replace(/^\/api/, '') // 路径重写:去掉 /api 前缀(按需调整)
}
}
}
})
5.3 环境变量配置(推荐,灵活切换环境)
在项目根目录新建 2 个环境变量文件,区分开发/生产环境,无需手动修改代码。
- 新建
.env.development(开发环境,本地开发用):
plain
# 开发环境接口基础路径(和 vite.config.js 中的 proxy 匹配)
VITE_API_URL = '/api'
- 新建
.env.production(生产环境,上线部署用):
plain
# 生产环境真实接口地址(替换为你的线上接口地址)
VITE_API_URL = 'http://api.xxx.com'
说明:开发环境走代理(/api 代理到后端地址),生产环境直接访问真实接口,无需修改封装代码。
5.4 Vue CLI 项目跨域配置(补充)
如果你的项目是 Vue3 CLI 搭建的(不是 Vite),修改项目根目录的 vue.config.js 文件:
javascript
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080', // 后端真实接口地址
changeOrigin: true, // 允许跨域
pathRewrite: { '^/api': '' } // 路径重写(按需调整)
}
}
}
}
六、完整报错处理方案
封装后的 axios 已经实现了统一报错,覆盖所有常见异常场景,无需在每个页面单独处理错误,大幅减少代码冗余:
- 网络异常:无响应(服务器未启动、网络中断),提示「网络异常,请检查网络或服务器状态」;
- 登录失效(401):自动清空 Token,提示「登录已失效,请重新登录」,并跳转到登录页;
- 无权限(403):提示「没有权限访问该接口」;
- 接口不存在(404):提示「请求接口不存在,请检查接口路径」;
- 服务器错误(500):提示「服务器异常,请稍后重试」;
- 其他业务报错:直接显示后端返回的错误信息(response.data.msg)。
七、注意事项(避坑指南)
- Token 存储:示例用 localStorage,若项目需要更安全的存储方式,可替换为 pinia/vuex 状态管理(刷新页面不丢失);
- 路由跳转:401 跳转登录页时,需先引入路由实例(import router from '.../router'),否则会报错;
- 跨域仅开发环境有效:生产环境跨域需后端配置 CORS(设置 Access-Control-Allow-Origin),前端代理配置不生效;
- Content-Type 注意 :上传文件需手动设置
multipart/form-data,普通 JSON 接口无需修改; - 环境变量命名 :Vite 环境变量必须以
VITE_开头,否则无法读取(比如 VITE_API_URL,不能写成 API_URL); - 代码复用:所有接口都复用封装的 request 实例,不要直接使用 axios 发起请求,否则无法触发拦截器。
八、总结
本文完整实现了 Vue3 + axios 前后端联调的核心实战内容,覆盖新手必学的三个核心知识点:
- axios 封装:统一配置、拦截器、报错处理,减少重复代码,提升项目维护性;
- 接口管理:模块化管理接口,按业务划分,后续修改接口路径更便捷;
- 跨域解决:适配 Vite/Vue CLI 项目,一键配置代理,解决本地开发跨域痛点;
- 报错处理:覆盖所有常见异常场景,统一提示,优化用户体验。