Angular CORS 與 Nginx
網上有幾個關於同一主題的問題,但沒有任何效果。
我有一個執行 Angular 應用程序的 serverXYZ、一個用於身份驗證的後端 tomcat webapp、一個 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,則使用描述的 conf 顯示應用程序,但我在身份驗證時收到 CORS 錯誤(CORS 請求失敗)。相反,如果我在 environment.ts 中使用帶有註釋字元串的配置,則瀏覽器身份驗證不會說 CORS,只是 403。當然,身份驗證 api 已經過測試並且可以正常工作。
我一頭霧水,怎麼了?此外,使用 nginx 解決這個問題是我的首選方式,但不是強制性的。
編輯: 我添加了更多資訊,我正在使用 “ng serve –disableHostCheck=true” 啟動 Angular 應用程序。我不知道在這種情況下是否應該使用“–publicHost”選項或“–host 0.0.0.0”?
編輯 2: 我剛才看到的另一件事,Firefox 在 OPTIONS 請求上沒有給我任何錯誤,只是在 POST 上出現 Cors。
您是否已經看過著名的If is Evil文章?文章指出
如果在位置上下文中,唯一可以在內部完成的 100% 安全的事情是:
return ...; rewrite ... last;
在大多數情況下,這些說明過於嚴格,通常您可以安全地使用塊
ngx_http_rewrite_module
內的任何 nginx 指令。if
但是,使用任何其他指令(包括該指令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; } }