JS跨域CORS方案
JS跨域CORS方案
引言
浏览器同源策略要求协议、域名、端口完全一致,前端页面访问另一个域名的接口就会被拦截报跨域错误。CORS是目前最标准、主流的跨域解决方式,由后端配合响应头放行。
什么是同源策略
三个任意一项不同都算跨域:
- 协议不同(http/https);
- 域名不同;
- 端口不同。
CORS后端响应头(PHP)
<?php
header('Access-Control-Allow-Origin: https://www.example.com');
header('Access-Control-Allow-Methods: GET,POST,OPTIONS');
header('Access-Control-Allow-Headers: Content-Type,Authorization');
header('Access-Control-Allow-Credentials: true');
携带cookie时Allow-Origin不能写*,必须指定具体域名,且前端请求withCredentials为true。
预检请求OPTIONS
POST JSON等复杂请求,浏览器会先发OPTIONS预检,后端要直接放行OPTIONS,返回204,否则正式请求发不出去。
其他常见跨域方式对比
- JSONP:只支持GET,老旧方案;
- Nginx反向代理:前端请求同源nginx,由nginx转发接口,无浏览器跨域;
- 开发环境代理:Vite、Webpack devServer proxy临时解决。
注意事项
- 生产不要用*放开所有来源;
- 区分简单请求和预检请求;
- 配合cookie要带Credentials并指定来源;
- 接口服务端做好来源校验。
总结
CORS是前后端分离首选方案,核心是后端设置允许来源、方法、响应头。复杂请求先处理OPTIONS预检,带cookie时指定具体域名,安全可控,比JSONP和代理更规范。
Nginx设置跨域,前端请求接口跨域配置示例
前言
前端页面和后端接口不在同一个域名下,浏览器报跨域错误。这是前后端分离开发最常见的问题。本文讲一下怎么用 Nginx 配置跨域。
什么是跨域
浏览器的同源策略:协议、域名、端口有一个不一样,就是跨域。
比如:
- 前端:
https://www.example.com - 后端接口:
https://api.example.com
这两个域名不一样,浏览器就不让前端直接请求后端接口。
Nginx 配置跨域
简单配置(允许所有域名)
在接口的 server 块里加:
server {
listen 443 ssl http2;
server_name api.example.com;
# 跨域配置
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
# 处理 OPTIONS 预检请求
if ($request_method = 'OPTIONS') {
return 204;
}
root /var/www/api;
index index.php;
}
指定允许的域名(推荐)
生产环境不要用 *,指定具体域名更安全:
# 允许单个域名
add_header Access-Control-Allow-Origin https://www.example.com;
# 允许多个域名
set $cors_origin "";
if ($http_origin ~* "^https://(www\.example\.com|m\.example\.com)$") {
set $cors_origin $http_origin;
}
add_header Access-Control-Allow-Origin $cors_origin;
带 Cookie 的跨域
如果跨域请求要带 Cookie,光加 * 不行:
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials true;
注意: 带 Cookie 的时候,Allow-Origin 不能用 *,必须指定具体域名。
完整配置示例
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/api.crt;
ssl_certificate_key /etc/nginx/ssl/api.key;
# 跨域配置
set $cors_origin "";
if ($http_origin ~* "^https://(www\.example\.com|admin\.example\.com)$") {
set $cors_origin $http_origin;
}
add_header Access-Control-Allow-Origin $cors_origin;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
# 处理 OPTIONS 预检请求
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $cors_origin;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
add_header Access-Control-Max-Age 86400;
return 204;
}
root /var/www/api;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}
检查配置并重载
nginx -t
nginx -s reload
常见坑
坑1:OPTIONS 请求 404
浏览器发 OPTIONS 预检请求,Nginx 直接返回 404。
原因: 没处理 OPTIONS 请求。
解决: 加上面那个 if ($request_method = 'OPTIONS') 的判断,直接返回 204。
坑2:跨域配置不生效
加了跨域配置还是报跨域错误。
原因1: PHP 后端也输出了跨域头,两边冲突了。
解决: 只留一处跨域配置,要么在 Nginx 配,要么在后端代码里配,不要两边都配。
原因2: Nginx 重载失败了。
解决: 确认 nginx -t 没问题,再 nginx -s reload。
坑3:带 Cookie 的跨域失败
配置了跨域,但是带 Cookie 请求还是失败。
原因: Allow-Origin 用了 *,浏览器不允许。
解决: 改成具体域名,加上 Access-Control-Allow-Credentials true。
坑4:POST 请求跨域失败
GET 请求没问题,POST 请求跨域了。
原因: 没允许 POST 方法或者 Content-Type 头。
解决: 把 POST 和 Content-Type 加到 Allow-Methods 和 Allow-Headers 里。
总结
| 配置项 | 作用 |
|---|---|
Access-Control-Allow-Origin |
允许哪个域名访问 |
Access-Control-Allow-Methods |
允许哪些请求方法 |
Access-Control-Allow-Headers |
允许哪些请求头 |
Access-Control-Allow-Credentials |
是否允许带 Cookie |
Access-Control-Max-Age |
预检请求缓存时间 |
生产环境建议: 不要用 *,指定具体域名更安全。
遇到问题加QQ23979811 协助处理