【Vue.js】Vue3全局配置Axios并解决跨域请求问题
一、背景与问题
在现代Web开发中,Axios作为主流的HTTP客户端库,其核心优势在于支持异步请求和拦截器功能。然而在Vue3项目中,开发者常遇到两个核心问题:
- 重复配置问题:每个API请求都需要手动配置
baseURL、headers等参数,导致代码冗余 - 跨域请求限制:浏览器出于安全策略的限制,会阻止跨域请求(CORS),导致
No 'Access-Control-Allow-Origin' header等错误
这两个问题在大型项目中尤为突出。例如一个电商系统需要频繁调用商品接口、用户接口、订单接口等,若不进行统一配置,代码可维护性将显著下降。
二、基本原理
1. Axios核心机制
Axios通过以下机制实现功能:
- 基于Promise的异步请求
- 支持拦截器(request/response)
- 内置的HTTP方法(GET/POST/PUT/DELETE等)
- 自动转换JSON数据
2. 跨域请求原理
浏览器出于安全考虑,执行以下限制:
- 同源策略(Same-origin policy):协议、域名、端口三者必须完全一致
- CORS预检请求(Preflight):对于非简单请求(如
Content-Type: application/json),浏览器会先发送OPTIONS请求
三、环境准备
1. 项目初始化
使用Vite创建Vue3项目:
npm create vue@latest2. 安装Axios
npm install axios3. 开发服务器配置(Vite)
在vite.config.js中配置代理:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, './src')
}
},
server: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})四、核心实现
1. 创建全局Axios实例
在src/utils/axios.js中创建配置:
// src/utils/axios.js
import axios from 'axios'
// 创建Axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_API_URL, // 从环境变量获取基础URL
timeout: 10000, // 超时时间
headers: {
'Content-Type': 'application/json'
}
})
// 请求拦截器
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 { data } = response
if (data.code === 200) {
return data.data
} else {
return Promise.reject(data.message)
}
},
error => {
// 处理网络错误
if (error.response) {
console.error('Server responded with status:', error.response.status)
} else {
console.error('Network error:', error.message)
}
return Promise.reject(error)
}
)
export default service2. 配置环境变量
在.env文件中设置基础URL:
VUE_APP_API_URL=https://api.example.com3. 跨域解决方案
开发环境代理
// vite.config.js
server: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}生产环境CORS配置
在后端服务器中设置响应头:
# Flask示例
@app.route('/api/data')
def get_data():
resp = make_response(json.dumps({'data': 'test'}))
resp.headers['Access-Control-Allow-Origin'] = '*'
return resp五、完整案例
1. 用户登录功能实现
前端代码(登录组件)
<template>
<div>
<input v-model="username" placeholder="用户名" />
<input v-model="password" type="password" placeholder="密码" />
<button @click="login">登录</button>
<p v-if="errorMsg">{{ errorMsg }}</p>
</div>
</template>
<script>
import { ref } from 'vue'
import axios from '@/utils/axios'
export default {
setup() {
const username = ref('')
const password = ref('')
const errorMsg = ref('')
const login = async () => {
try {
const res = await axios.post('/api/login', {
username: username.value,
password: password.value
})
console.log('登录成功:', res)
// 处理登录成功逻辑
} catch (err) {
errorMsg.value = err.message
}
}
return { username, password, errorMsg, login }
}
}
</script>后端接口示例(Node.js)
// server.js
const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors())
app.use(express.json())
app.post('/api/login', (req, res) => {
const { username, password } = req.body
// 模拟验证逻辑
if (username === 'admin' && password === '123456') {
res.json({ code: 200, message: '登录成功', data: { token: 'fake-token' } })
} else {
res.status(401).json({ code: 401, message: '账号或密码错误' })
}
})
app.listen(3000, () => {
console.log('Server running at http://localhost:3000')
})六、源码解析
1. 请求拦截器逻辑
service.interceptors.request.use(
config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
error => {
return Promise.reject(error)
}
)- 从本地存储获取token
- 将token添加到请求头
- 如果获取失败,返回错误Promise
2. 响应拦截器逻辑
service.interceptors.response.use(
response => {
const { data } = response
if (data.code === 200) {
return data.data
} else {
return Promise.reject(data.message)
}
},
error => {
if (error.response) {
console.error('Server responded with status:', error.response.status)
} else {
console.error('Network error:', error.message)
}
return Promise.reject(error)
}
)- 检查响应码是否为200
- 如果成功,返回数据部分
- 如果失败,返回错误信息
- 处理网络错误和服务器错误
七、进阶使用
1. 动态环境配置
// 根据环境变量切换API地址
const service = axios.create({
baseURL: process.env.NODE_ENV === 'production'
? 'https://api.example.com'
: 'https://api-dev.example.com'
})2. 请求重试机制
// 添加重试逻辑
service.interceptors.request.use(config => {
config.retries = 3
config.retry = (count, response) => {
if (count >= config.retries) return Promise.reject(response)
return new Promise(resolve => {
setTimeout(() => {
resolve(config)
}, 1000)
})
}
return config
})3. 请求缓存机制
// 添加请求缓存
const cache = new Map()
service.interceptors.request.use(config => {
const key = `${config.method}:${config.url}:${JSON.stringify(config.data)}`
if (cache.has(key)) {
return Promise.resolve(cache.get(key))
}
return Promise.resolve(config)
})
service.interceptors.response.use(
response => {
const key = `${response.config.method}:${response.config.url}:${JSON.stringify(response.config.data)}`
cache.set(key, response.data)
return response.data
}
)八、性能与工程实践
1. 性能优化策略
- 使用
axios-cache-adapter实现请求缓存 - 使用
axios-multipart处理文件上传 - 配置
timeout避免长时间阻塞 - 使用
compression中间件压缩响应数据
2. 安全风险分析
- 暴露
token可能导致安全漏洞 - 跨域配置不当可能导致CSRF攻击
- 未加密的敏感数据传输存在泄露风险
- 需要配合HTTPS使用
3. 异常处理建议
- 在全局组件中添加错误处理
- 使用
try/catch包裹异步请求 配置
errorHandler全局处理// main.js app.config.errorHandler = (err, vm, info) => { console.error('全局错误处理:', err, info) }
九、常见问题与踩坑
1. 跨域问题解决方案
# 问题现象:出现"No 'Access-Control-Allow-Origin' header"
# 解决方案:
# 1. 开发环境使用代理配置
# 2. 生产环境配置CORS头
# 3. 使用HTTPS服务2. 拦截器未生效问题
// 常见错误:未正确引入Axios实例
import axios from 'axios'
// 正确做法
import axios from '@/utils/axios'3. 环境变量未生效问题
// 常见错误:未在构建时注入环境变量
// 正确做法:使用.env文件,确保文件在项目根目录4. 请求头未携带token问题
// 常见错误:未正确配置headers
// 正确做法:在拦截器中动态添加Authorization头十、最佳实践
1. 推荐配置方案
- 使用环境变量管理配置
- 配置统一的API基础URL
- 添加请求和响应拦截器
- 配置合理的超时时间
- 使用HTTPS进行安全传输
2. 使用建议
- 在开发环境使用代理配置
- 在生产环境配置CORS头
- 对敏感接口进行身份验证
- 对关键请求添加重试机制
- 对频繁请求进行缓存处理
3. 避免使用场景
- 轻量级页面无需全局配置
- 需要动态切换不同API接口时
- 项目规模较小且请求量较少时
- 需要高度定制化请求配置时
十一、总结
通过全局配置Axios,我们实现了:
- 代码的复用和可维护性提升
- 跨域请求的统一处理
- 请求的统一拦截和处理
- 更好的错误处理机制
在实际开发中,应根据项目规模和需求选择合适的配置方式。对于大型项目,建议:
- 使用环境变量管理配置
- 配置详细的拦截器逻辑
- 实现安全的请求处理
- 配置合理的性能优化策略
需要注意的是,过度使用拦截器可能导致性能下降,建议对关键请求进行合理配置。同时,要时刻关注安全风险,确保敏感信息不会被泄露。通过合理配置Axios,我们可以构建更加健壮、可维护的Vue3项目。