如何在 nginx 的上游错误上设置 Access-Control-Allow-Origin?
How do I set Access-Control-Allow-Origin on upstream errors in nginx?
我知道“如何在 nginx 中设置 Access-Control-Allow-Origin”有上百万个答案,但不幸的是,如果我的具体问题有答案,它会被所有基本答案淹没。
我有一个 Angular 应用程序指向一个 nginx 服务器,上游有一个休息服务 - 所有 运行 在我的本地笔记本电脑上 docker 组成。
nginx 服务配置相当简单:
upstream REST {
# rest-service is mapped by docker-compose to the correct container
server rest-service:8080;
}
server {
listen 80;
listen [::]:80;
# This is mapped in /etc/hosts on my laptop
server_name rest-api.mylocal.com;
location / {
proxy_hide_header 'Access-Control-Allow-Origin';
# web-ui is also mapped in /etc/hosts on my laptop
add_header "Access-Control-Allow-Origin" "http://web-ui.mylocal.com";
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Max-Age' 1728000; # 20 days
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header Reverse-Proxy true;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://REST;
}
}
如果我在其余服务上调用有效的 URL,例如http://rest-api.mylocal.com/api/v1/auth/config
(这是一个未经身份验证的端点),一切正常:
curl -v 'http://rest-api.mylocal.com/api/v1/auth/config'
...
< Access-Control-Allow-Origin: http://web-ui.mylocal.com
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
< Access-Control-Max-Age: 1728000
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Content-Type, Authorization
< Reverse-Proxy: true
<
* Connection #0 to host rest-api.mylocal.com left intact
{"status":"OK","name":"foo",...}* Closing connection 0
但是,如果我调用无效的 URL,比如 http://rest-api.mylocal.com/api/v1/accounts
(这是一个经过身份验证的端点,我没有提供凭据),我会返回预期的错误,但没有 CORS headers。在浏览器中,这会导致一切都崩溃,所以我什至没有在 Angular 中收到要显示给用户的错误消息:
curl -v 'http://rest-api.mylocal.com/api/v1/accounts'
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to rest-api.mylocal.com (127.0.0.1) port 80 (#0)
> GET /api/v1/accounts HTTP/1.1
> Host: rest-api.mylocal.com
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 403
< Server: nginx/1.21.6
< Date: Wed, 09 Feb 2022 20:57:49 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: JSESSIONID=F3B21A55841C8E5A6F838F2427A0E22B; Path=/; HttpOnly
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
<
* Connection #0 to host rest-api.mylocal.com left intact
{"timestamp":"2022-02-09T20:57:49.526+00:00","status":403,"error":"Forbidden","message":"Access Denied","path":"/api/v1/accounts"}* Closing connection 0
浏览器控制台:
Access to XMLHttpRequest at 'http://rest-api.mylocal.com/api/v1/accounts' from origin 'http://web-ui.mylocal.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
那么...有没有办法确保 CORS headers 仍然被 nginx 添加到响应中,即使来自上游服务器的响应是错误的(401/403/404/等) )?
您需要将 always
添加到每个要添加到错误响应中的 header。它是在 1.7.5 中添加的:https://nginx.org/r/add_header
我知道“如何在 nginx 中设置 Access-Control-Allow-Origin”有上百万个答案,但不幸的是,如果我的具体问题有答案,它会被所有基本答案淹没。
我有一个 Angular 应用程序指向一个 nginx 服务器,上游有一个休息服务 - 所有 运行 在我的本地笔记本电脑上 docker 组成。
nginx 服务配置相当简单:
upstream REST {
# rest-service is mapped by docker-compose to the correct container
server rest-service:8080;
}
server {
listen 80;
listen [::]:80;
# This is mapped in /etc/hosts on my laptop
server_name rest-api.mylocal.com;
location / {
proxy_hide_header 'Access-Control-Allow-Origin';
# web-ui is also mapped in /etc/hosts on my laptop
add_header "Access-Control-Allow-Origin" "http://web-ui.mylocal.com";
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Max-Age' 1728000; # 20 days
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header Reverse-Proxy true;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://REST;
}
}
如果我在其余服务上调用有效的 URL,例如http://rest-api.mylocal.com/api/v1/auth/config
(这是一个未经身份验证的端点),一切正常:
curl -v 'http://rest-api.mylocal.com/api/v1/auth/config'
...
< Access-Control-Allow-Origin: http://web-ui.mylocal.com
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
< Access-Control-Max-Age: 1728000
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Content-Type, Authorization
< Reverse-Proxy: true
<
* Connection #0 to host rest-api.mylocal.com left intact
{"status":"OK","name":"foo",...}* Closing connection 0
但是,如果我调用无效的 URL,比如 http://rest-api.mylocal.com/api/v1/accounts
(这是一个经过身份验证的端点,我没有提供凭据),我会返回预期的错误,但没有 CORS headers。在浏览器中,这会导致一切都崩溃,所以我什至没有在 Angular 中收到要显示给用户的错误消息:
curl -v 'http://rest-api.mylocal.com/api/v1/accounts'
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to rest-api.mylocal.com (127.0.0.1) port 80 (#0)
> GET /api/v1/accounts HTTP/1.1
> Host: rest-api.mylocal.com
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 403
< Server: nginx/1.21.6
< Date: Wed, 09 Feb 2022 20:57:49 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: JSESSIONID=F3B21A55841C8E5A6F838F2427A0E22B; Path=/; HttpOnly
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
<
* Connection #0 to host rest-api.mylocal.com left intact
{"timestamp":"2022-02-09T20:57:49.526+00:00","status":403,"error":"Forbidden","message":"Access Denied","path":"/api/v1/accounts"}* Closing connection 0
浏览器控制台:
Access to XMLHttpRequest at 'http://rest-api.mylocal.com/api/v1/accounts' from origin 'http://web-ui.mylocal.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
那么...有没有办法确保 CORS headers 仍然被 nginx 添加到响应中,即使来自上游服务器的响应是错误的(401/403/404/等) )?
您需要将 always
添加到每个要添加到错误响应中的 header。它是在 1.7.5 中添加的:https://nginx.org/r/add_header