nginx配置以启用具有原点匹配的CORS

时间:2019-01-22 17:08:35

标签: nginx cors cross-domain preflight

我已经尝试对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?也许有某种方法可以克服这种限制?

3 个答案:

答案 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 是最正确的答案...