跨域不是后端"不让你访问"
先纠正一个常见误解:跨域限制是浏览器施加的,服务端其实收到了请求。这也是为什么 Postman 测得好好的,浏览器里却报错。
同源的定义
协议、域名、端口三者完全相同才算同源。
http://localhost:5173 → http://localhost:8080 ✗ 端口不同
https://a.com → http://a.com ✗ 协议不同
https://a.com → https://api.a.com ✗ 域名不同
简单请求与预检请求
触发预检(OPTIONS)的条件之一是"非简单请求":自定义请求头(比如带上 Authorization)、Content-Type 为 application/json,都会触发预检。
服务端需要正确响应 OPTIONS:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOriginPatterns("http://localhost:*") // 开发环境
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600); // 预检结果缓存 1 小时,减少 OPTIONS 请求
}
}
携带凭证时的两个硬性要求
如果你要在请求中带 Cookie(withCredentials = true):
Access-Control-Allow-Origin不能为*,必须明确指定来源- 必须同时返回
Access-Control-Allow-Credentials: true
这也是很多"配置了还是报错"的根本原因。
生产环境:推荐用反向代理,而不是 CORS
上线后前后端通常同域,用 Nginx 把 API 路径转发到后端即可,从根上避开跨域:
server {
listen 443 ssl;
server_name your-domain.com;
location / {
root /var/www/dist;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
前端请求 /api/xxx,同源,没有跨域,也不用在代码里写死后端地址。
小结
开发环境用 CORS 放开方便调试,生产环境优先用反向代理收敛。把这两件事分清,跨域问题基本不会再困扰你。
