Nginx 允许多个域名跨域访问

Posted by Sunday on 2019-08-09

允许指定单个域名跨域访问

1
2
3
4
5
6
7
8
9
10
11
location /{
#add_header Access-Control-Allow-Origin *; #允许所有域名不安全
add_header 'Access-Control-Allow-Origin' 'https://www.sundayle.com';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,X-Requested-With';
if ($request_method = 'OPTIONS') {
return 204;
}
...
}

第一条指令:接受www.sundayle.com 跨域请求
第二条指令:当该标志为真时,响应于该请求是否可以被暴露(可选)
第三条指令:指定请求的方法,可以是GET, POST, OPTIONS, PUT, DELETE等(可选)
第四条指令:允许脚本访问的返回头(可选)
第五条指令:给OPTIONS 添加 204的返回,是为了处理在发送POST请求时Nginx依然拒绝访问的错误,发送”预检请求”时,需要用到方法 OPTIONS ,所以服务器需要允许该方法。

允许多个域名跨域访问

方法一:使用IF(不建议)

虚拟主机比较多,不方便

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server {
set $allow_origin "";
if ( $http_origin ~ '^https?://(www|m).sundayle.com' ) {
set $allow_origin $http_origin;
}
location /{
add_header 'Access-Control-Allow-Origin' $allow_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Token,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,X_Requested_With,If-Modified-Since,Cache-Control,Content-Type';
if ($request_method = 'OPTIONS') {
return 204;
}
...
}

方法二:使用MAP(建议)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
map $http_origin $allow_origin {
default "";
"~^(https?://localhost(:[0-9]+)?)" $1;
"~^(https?://127.0.0.1(:[0-9]+)?)" $1;
"~^(https?://192.168.10.[\d]+(:[0-9]+)?)" $1;
"~^https://www.sunday.com" https://www.sundayle.com;
"~^https://m.sundayle.com" https://m.sundayle.com;
"~^(https?://[\w]+.open.sundayle.com)" $1;
#"~^(https?://([\w]+.)?[\w]+.open.sundayle.com)" $1; #允许一级和二级域名

}

server {
location /{
add_header 'Access-Control-Allow-Origin' $allow_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Token,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,X_Requested_With,If-Modified-Since,Cache-Control,Content-Type';
if ($request_method = 'OPTIONS') {
return 204;
}
...
}

跨域测试

1
2
3
4
curl -I -X OPTIONS -H "Origin: https://www.sundayle.com" "https://api.sundayle.com"
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.sundayle.com
...

其他

Nginx 更多判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://www.sundayle.com';
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';
add_header 'Access-Control-Max-Age' 1728000; # 20days
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' 'https://www.sundayle.com';
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';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' 'https://www.sundayle.com';
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';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}

Apache中启用CORS
在httpd配置或.htaccess文件中添加如下语句

1
2
SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1  
Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN

PHP中启用CORS
通过在服务端设置Access-Control-Allow-Origin响应头

允许所有来源访问

1
2
3
<?php
header("Access-Control-Allow-Origin: *");
?>

允许来自特定源的访问

1
2
3
<?php
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
?>

配置多个访问源
由于浏览器实现只支持了单个origin、*、null,如果要配置多个访问源,可以在代码中处理如下

1
2
3
4
5
6
7
8
9
10
<?php
$allowe_origin = array(
"http://www.example.com" ,
"http://app.example.com" ,
"http://cms.example.com" ,
);
if (in_array($_SERVER['HTTP_ORIGIN'], $allowe_origin)){
@header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
}
?>

HTML中启用CORS

1
<meta http-equiv="Access-Control-Allow-Origin" content="*">

参考链接

正则表达式在线测试
Nginx 通过 CORS 实现跨域
阮一峰 跨域资源共享 CORS 详解