我已经尝试对nginx使用a very popular config,它可以启用CORS并支持使用正则表达式进行原点匹配。
这是我的配置:
server {
listen 80 default_server;
root /var/www;
location / {
if ($http_origin ~ '^http://(www\.)?example.com$') {
add_header Access-Control-Allow-Origin "$http_origin";
}
# Handling preflight requests
if ($request_method = OPTIONS) {
add_header Content-Type text/plain;
add_header Content-Length 0;
return 204;
}
}
}
但是,此配置必须使用两个条件:一个条件匹配原始域名,另一个条件捕获预检请求。因此,当第二个条件匹配时,第一个条件的标头不会添加到响应中。
根据If Is Evil官方文章,这是nginx的预期行为。
如果If Is Evil
如何在nginx中启用CORS?也许有某种方法可以克服这种限制?
答案 0 :(得分:1)
您可以尝试使用map
而不是第一个if
块:
map $http_origin $allow_origin {
~^http://(www\.)?example.com$ $http_origin;
}
map $http_origin $allow_methods {
~^http://(www\.)?example.com$ "OPTIONS, HEAD, GET";
}
server {
listen 80 default_server;
root /var/www;
location / {
add_header Access-Control-Allow-Origin $allow_origin;
add_header Access-Control-Allow-Methods $allow_methods;
# Handling preflight requests
if ($request_method = OPTIONS) {
add_header Content-Type text/plain;
add_header Content-Length 0;
return 204;
}
}
}
nginx将拒绝添加空的HTTP标头,因此只有在请求中存在Origin
标头并匹配此正则表达式时,才会添加它们。
答案 1 :(得分:1)
到目前为止,我发现的only solution是一种利用变量来聚合多个条件,然后仅将其与单个if语句匹配的黑客,因此重复了一些指令:
server {
listen 80 default_server;
root /var/www;
location / {
set $cors '';
set $cors_allowed_methods 'OPTIONS, HEAD, GET';
if ($http_origin ~ '^https?://(www\.)?example.com$') {
set $cors 'origin_matched';
}
# Preflight requests
if ($request_method = OPTIONS) {
set $cors '${cors} & preflight';
}
if ($cors = 'origin_matched') {
add_header Access-Control-Allow-Origin $http_origin;
}
if ($cors = 'origin_matched & preflight') {
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Methods $cors_allowed_methods;
add_header Content-Type text/plain;
add_header Content-Length 0;
return 204;
}
}
}
答案 2 :(得分:0)
没有深入了解nginx设置的细节,因为它返回的CORS标头不正确,所以无论如何都无法正常工作。
特别是:
对于飞行前(OPTIONS)请求,以下是唯一有意义的CORS响应标头:Access-Control-Allow Origin
,(必需),Access-Control-Allow Credentials
(可选),{ {1}},(必需),Access-Control-Allow-Methods
,(必需)和Access-Control-Allow-Headers
(可选)。其他任何人都将被忽略。
对于常规(非选项)请求,以下是唯一有意义的CORS响应标头:Access-Control-Max-Age
(必需),Access-Control-Allow Origin
(可选)和Access-Control-Allow Credentials
(可选)。其他任何人都将被忽略。
请注意飞行前请求的那些必需标头-当前,您仅传递了其中两个...另外,请注意,您不需要需要返回Access-Control-Expose-Headers
用于非OPTIONS请求-它不是“有效”请求,因此将被忽略。
就您的特定nginx问题而言,我认为 @Slava Fomin II 是最正确的答案...