前言
跨域问题是前端开发中常见的挑战,本文将系统介绍从本地开发到生产环境部署的全链路跨域解决方案,涵盖Vue项目代理配置、Nginx服务器配置和后端接口设置。
理解跨域问题
跨域问题源于浏览器的同源策略(Same-Origin Policy),它限制了不同源之间的资源交互。当协议、域名或端口任一不同时,就会产生跨域问题。
常见表现:
1.前端控制台出现 Access-Control-Allow-Origin 相关错误
2.预检请求(OPTIONS)失败
3.接口请求被浏览器拦截
Vue项目本地开发代理配置
在本地开发时,我们可以利用Vue CLI或Vite的代理功能解决跨域问题。
1. Vue CLI项目配置
在 vue.config.js 中配置代理:
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://backend-service.com', // 后端接口地址
changeOrigin: true, // 是否改变源
pathRewrite: {
'^/api': '' // 重写路径
},
secure: false // 如果是https接口,需要配置这个参数
}
}
}
}
2. Vite项目配置
在 vite.config.js 中配置代理:
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://backend-service.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})
3. 本地开发环境变量配置
(vue2)建议将代理目标地址配置在环境变量中:
.env.development 文件:
VUE_APP_BASE_URL="/api"
然后在代码中使用:
const response = awaitfetch(`${process.env.VUE_APP_BASE_URL}/user`);
(vue3)建议将代理目标地址配置在环境变量中:
.env.development 文件:
VITE_API_BASE_URL=/api
然后在代码中使用:
const response = await fetch(`${import.meta.env.VITE_API_BASE_URL}/user`);
生产环境Nginx跨域配置
项目部署后,通常通过Nginx反向代理解决跨域问题。
1. 基本Nginx跨域配置
server {
listen 80;
server_name your-domain.com;
location /api {
proxy_pass http://backend-service.com;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 堆代码 duidaima.com
# 跨域相关配置
add_header 'Access-Control-Allow-Origin' '$http_origin';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
# 处理OPTIONS预检请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}
location / {
root /path/to/your/frontend/dist;
try_files $uri $uri/ /index.html;
}
}
2. 多域名跨域配置
如果需要支持多个域名跨域:
map $http_origin $cors_origin {
default "";
"~^https://domain1.com" "https://domain1.com";
"~^https://domain2.com" "https://domain2.com";
}
server {
# ...其他配置
add_header 'Access-Control-Allow-Origin' $cors_origin;
}
3. 静态资源缓存与跨域
对于带hash的静态资源,可以设置长期缓存并允许跨域:
location ~* \.(js|css|png|jpg|jpeg|gif|ico|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header 'Access-Control-Allow-Origin' '*';
}
后端接口跨域设置
除了前端配置,后端也需要进行相应的跨域设置。
1. Node.js (Express) 跨域设置
const express = require('express');
const cors = require('cors');
const app = express();
// 基本CORS配置
app.use(cors());
// 自定义CORS配置
app.use(cors({
origin: ['https://your-frontend-domain.com', 'https://another-domain.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400
}));
// 手动设置CORS
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://your-frontend-domain.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Max-Age', '86400');
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
2. Spring Boot 跨域设置
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("https://your-frontend-domain.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
或使用注解方式:
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "https://your-frontend-domain.com",
allowedHeaders = "*",
allowCredentials = "true",
maxAge = 3600)
public class ApiController {
// 控制器方法
}
3. Django 跨域设置
安装django-cors-headers包:
# settings.py
INSTALLED_APPS = [
...
'corsheaders',
]
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
]
# 基本配置
CORS_ALLOW_ALL_ORIGINS = True
# 或精细控制
CORS_ALLOWED_ORIGINS = [
"https://your-frontend-domain.com",
"https://another-domain.com"
]
CORS_ALLOW_METHODS = [
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
]
CORS_ALLOW_HEADERS = [
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
]
CORS_ALLOW_CREDENTIALS = True
CORS_PREFLIGHT_MAX_AGE = 86400
特殊场景处理
1. WebSocket跨域
Nginx配置WebSocket跨域:
location /ws/ {
proxy_pass http://websocket-backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
# CORS设置
add_header 'Access-Control-Allow-Origin' '$http_origin';
add_header 'Access-Control-Allow-Credentials' 'true';
}
2. 携带凭证的跨域请求
当请求需要携带cookie或认证信息时:
前端:
fetch('https://api.domain.com/data', {
credentials: 'include'
});
后端响应头必须包含:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://your-frontend-domain.com // 不能是*
3. 自定义请求头跨域
当请求包含自定义头时:
前端:
fetch('https://api.domain.com/data', {
headers: {
'X-Custom-Header': 'value'
}
});
后端响应头必须包含:
Access-Control-Allow-Headers: X-Custom-Header
安全注意事项
1. 不要过度放宽跨域限制:生产环境应明确指定允许的源,避免使用 *
2. 合理设置缓存时间:Access-Control-Max-Age 不宜设置过长
3. 敏感操作需要额外保护:即使跨域设置正确,敏感操作仍需CSRF保护
4. HTTPS安全:生产环境应使用HTTPS,确保数据传输安全
总结
跨域问题的解决需要前后端协同配合。在开发阶段,前端可以通过代理解决;在生产环境,推荐使用Nginx反向代理或后端配置CORS。根据项目实际需求选择合适的解决方案,并始终牢记安全最佳实践。