使用 Nginx 的 Angular CORS

使用 Nginx 的 Angular CORS

网上针对同一主题提出了几个问题,但都没有任何效果。

我有一个 serverXYZ,运行着一个 Angular 应用程序、一个用于身份验证的后端 tomcat web 应用程序和一个 nginx 服务器。Angular 应用程序在端口 4200 上,tomcat 应用程序在端口 8080 上。所有内容都在同一台主机上。

角度应用程序有一个 environment.ts 文件(注释的字符串是我的测试之一,请参阅下面的 nginx conf):

export const environment = {
  production: false,
//  apiUrl: 'http://serverXYZ:444/api'
  apiUrl: 'http://localhost:8080/backend'
};

nginx 配置:

    server {
        listen 444;
    
            server_name serverXYZ;

            location / {
                    proxy_pass http://localhost:4200;
                    
                    //websocket
                    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;
                    proxy_pass_request_headers on;
                    proxy_http_version 1.0;
                    proxy_set_header Upgrade $http_upgrade;
                    proxy_set_header Connection "Upgrade";
                    proxy_read_timeout 120s;
            
                    if ($request_method = 'OPTIONS') {
                            add_header 'Access-Control-Allow-Origin' '*';
                            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;
                            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' '*';
                            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' '*';
                            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';
                    }
    
            }

            location /api {
                proxy_pass http://localhost:8080/backend;

                if ($request_method = 'OPTIONS') {
                        add_header 'Access-Control-Allow-Origin' '*';
                        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;
                        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' '*';
                        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' '*';
                        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';
                }

           }
}

后端 tomcat 应用程序在其 web.xml 中有以下内容:

...
<!-- Tomcat built in CORS implementation -->
        <!--  https://tomcat.apache.org/tomcat-7.0-doc/config/filter.html -->
        <filter>
                <filter-name>CorsFilter</filter-name>
                <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
                <init-param>
                        <param-name>cors.allowed.headers</param-name>
                        <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization</param-value>
                </init-param>
                <init-param>
                    <param-name>cors.allowed.methods</param-name>
                    <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
                </init-param>
        </filter>
        <filter-mapping>
                <filter-name>CorsFilter</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>
        <!-- End of built in CORS implementation -->
...

我使用我的电脑,打开浏览器,使用所述配置,如果我连接到 http://serverXYZ:444,应用程序就会显示出来,但我在身份验证时收到 CORS 错误(CORS 请求失败)。如果我使用 environment.ts 中注释字符串的配置,浏览器身份验证不会显示 CORS,只会显示 403。当然,身份验证 API 已经过测试并正常运行。

我完全不知道,出了什么问题?另外,使用 nginx 解决这个问题是我的首选方法,但不是强制性的。

编辑: 我再补充一条信息,我使用“ng serve --disableHostCheck=true”启动了 angular 应用程序。我不知道在这种情况下是否应该使用“--publicHost”选项或“--host 0.0.0.0”?

编辑2: 我刚刚看到的另一件事是,Firefox 在 OPTIONS 请求上没有给我任何错误,只有在 POST 上才出现 Cors。

答案1

你看过著名的如果是邪恶的文章?文章指出

在位置上下文中可以完成的唯一 100% 安全的事情是:

return ...;
rewrite ... last;

在大多数情况下,这些说明过于严格,通常你可以安全地使用来自ngx_http_rewrite_moduleif块内。但是使用包括该指令在内的任何其他指令add_header都非常不安全,并且可能导致不可预测的结果。下面是我编写此类配置的方法:

map $request_method $route {
    GET        main;
    POST       main;
    OPTIONS    options;
    default    invalid;
}

map $request_method $api {
    GET        api;
    POST       api;
    OPTIONS    options;
    default    invalid;
}

server {
    listen 444;
    server_name serverXYZ;

    location / {
        try_files /dev/null @$route;
    }

    location /api {
        try_files /dev/null @$api;
    }

    location @main {
        # websocket conntection setup
        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;
        proxy_pass_request_headers on;
        proxy_http_version 1.0;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_read_timeout 120s;
        # pass the request
        proxy_pass http://localhost:4200;
        # add response CORS headers
        add_header 'Access-Control-Allow-Origin' '*';
        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';
    }

    location @api {
        # transform the URI        
        rewrite ^/api(.*) /backend$1 break;
        # pass the request
        proxy_pass http://localhost:8080;
        # add response CORS headers
        add_header 'Access-Control-Allow-Origin' '*';
        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';
    }

    location @options {
        add_header 'Access-Control-Allow-Origin' '*';
        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;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 204;
    }

    location @invalid {
        # method not allowed
        add_header Allow "GET, POST, OPTIONS";
        return 405;
    }
}

相关内容