第一次在Vue项目里看到控制台弹出"CORS policy"红色报错时,我盯着屏幕愣了半天。明明后端接口已经返回了数据,浏览器却死活不肯给我。后来才明白,这是浏览器同源策略在作祟——它像一位过度负责的保安,坚决阻止不同源的资源交互。
同源策略要求三个关键要素完全一致:
现代前端开发普遍采用前后端分离架构,本地开发时经常遇到:
这时候浏览器就会抛出经典错误:
javascript复制Access to XMLHttpRequest at 'http://localhost:5000/api' from origin 'http://localhost:8080'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present...
最正统的解决方案是让后端在响应头中添加:
http复制Access-Control-Allow-Origin: *
但现实开发中常遇到:
利用<script>标签不受同源策略限制的特性:
javascript复制function handleResponse(data) {
console.log(data)
}
const script = document.createElement('script')
script.src = 'http://api.com/data?callback=handleResponse'
document.body.appendChild(script)
但致命缺陷是:
这才是Vue开发者的首选方案,其原理如图:
code复制浏览器(8080) → 代理服务器(8080) → 后端API(5000)
优势在于:
在项目根目录创建/修改vue.config.js:
javascript复制module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
pathRewrite: {
'^/api': '' // 移除请求路径中的/api
}
}
}
}
}
关键参数说明:
target:实际后端地址changeOrigin:修改请求头中的host值pathRewrite:路径重写规则对应的axios请求示例:
javascript复制axios.get('/api/users').then(res => {
// 实际请求会发送到 http://localhost:5000/users
})
当项目需要对接多个后端服务时:
javascript复制module.exports = {
devServer: {
proxy: {
'/auth': {
target: 'http://auth.server.com',
pathRewrite: { '^/auth': '' }
},
'/api': {
target: 'http://api.server.com',
pathRewrite: { '^/api': '' }
}
}
}
}
前端调用时只需区分前缀:
javascript复制// 认证服务
axios.post('/auth/login', credentials)
// 业务API
axios.get('/api/products')
在项目根目录创建:
.env.development(开发环境).env.production(生产环境)示例内容:
ini复制# .env.development
VUE_APP_API_BASE=/dev-api
VUE_APP_AUTH_BASE=/dev-auth
# .env.production
VUE_APP_API_BASE=/prod-api
VUE_APP_AUTH_BASE=/prod-auth
改造vue.config.js:
javascript复制module.exports = {
devServer: {
proxy: {
[process.env.VUE_APP_API_BASE]: {
target: 'http://localhost:5000',
pathRewrite: {
[`^${process.env.VUE_APP_API_BASE}`]: ''
}
}
}
}
}
创建src/utils/request.js:
javascript复制import axios from 'axios'
const service = axios.create({
baseURL: process.env.VUE_APP_API_BASE,
timeout: 30000
})
// 请求拦截器
service.interceptors.request.use(config => {
// 可在此处添加token等
return config
})
// 响应拦截器
service.interceptors.response.use(
response => response.data,
error => {
// 统一错误处理
return Promise.reject(error)
}
)
export default service
配置文件位置错误
vue.config.js在项目根目录src/目录下服务未重启
路径重写问题
pathRewrite规则是否匹配环境变量未加载
VUE_APP_开头开发环境用webpack代理,生产环境则需要:
示例Nginx配置:
nginx复制location /api/ {
proxy_pass http://backend-server;
proxy_set_header Host $host;
}
在对接未完成的后端接口时,可以:
javascript复制devServer: {
proxy: {
'/api': {
target: 'http://localhost:5000',
bypass: function(req) {
if (req.url.includes('/special-api')) {
return '/mock/special.json'
}
}
}
}
}
这个配置让我在等后端开发时,能先用本地JSON文件模拟接口返回,等真实接口完成后只需移除bypass函数即可无缝切换。