Appearance
跨域配置
跨域资源共享(CORS)允许浏览器向跨源服务器发出XMLHttpRequest请求。
基本配置
简单配置
nginx
add_header 'Access-Control-Allow-Origin' '*';指定域名
nginx
add_header 'Access-Control-Allow-Origin' 'https://www.example.com';完整CORS配置
标准配置
nginx
server {
listen 80;
server_name api.example.com;
# CORS头
add_header 'Access-Control-Allow-Origin' 'https://www.example.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
add_header 'Access-Control-Max-Age' 1728000 always;
# OPTIONS请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
location / {
proxy_pass http://backend;
}
}多域名配置
允许多个域名
nginx
map $http_origin $cors_origin {
default "";
"https://www.example.com" $http_origin;
"https://api.example.com" $http_origin;
}
server {
listen 80;
server_name api.example.com;
add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
location / {
proxy_pass http://backend;
}
}静态资源跨域
字体文件
nginx
location ~* \.(woff|woff2|ttf|otf|eot)$ {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
expires 1y;
add_header Cache-Control "public, immutable";
}图片文件
nginx
location ~* \.(jpg|jpeg|png|gif|webp|svg)$ {
add_header Access-Control-Allow-Origin "*";
expires 30d;
add_header Cache-Control "public";
}API跨域
RESTful API
nginx
server {
listen 80;
server_name api.example.com;
# CORS配置
add_header 'Access-Control-Allow-Origin' 'https://www.example.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
# OPTIONS请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}预检请求
处理OPTIONS请求
nginx
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}凭证请求
允许携带凭证
nginx
add_header 'Access-Control-Allow-Origin' 'https://www.example.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;注意: 允许凭证时,Access-Control-Allow-Origin不能设置为"*"
完整示例
生产环境配置
nginx
map $http_origin $cors_origin {
default "";
"https://www.example.com" $http_origin;
"https://admin.example.com" $http_origin;
}
server {
listen 80;
server_name api.example.com;
# CORS配置
add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range,X-Custom-Header' always;
add_header 'Access-Control-Max-Age' 1728000 always;
# 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,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
location /api/ {
proxy_pass http://backend;
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;
}
}常见问题
跨域请求失败
原因: Access-Control-Allow-Origin设置错误
解决: 检查Origin头
nginx
add_header 'Access-Control-Allow-Origin' 'https://www.example.com';预检请求失败
原因: 未正确处理OPTIONS请求
解决: 添加OPTIONS请求处理
nginx
if ($request_method = 'OPTIONS') {
return 204;
}凭证请求失败
原因: Access-Control-Allow-Origin设置为"*"
解决: 设置具体域名
nginx
add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
add_header 'Access-Control-Allow-Credentials' 'true';总结
跨域配置的关键点:
- Access-Control-Allow-Origin:设置允许的源
- Access-Control-Allow-Methods:设置允许的方法
- Access-Control-Allow-Headers:设置允许的请求头
- OPTIONS请求:正确处理预检请求
- 凭证请求:允许携带凭证
合理配置CORS,解决跨域访问问题。