如何将 Nginx 中的 POST/PUT/... 重新路由到内部服务?
How to reroute POST/PUT/... in Nginx to internal service?
我有一台安装了 nginx 的服务器(ubuntu 20.04 内核)。在同一台服务器上,我在端口 8080 上有一个 运行 Spring Boot Web(2.3.3.RELEASE) 服务。
我想从 Spring 外部引导 Web 服务访问资源
例如http:///server/api/users 访问 http://localhost/api/users 和 return 对客户端的响应。
我在 nginx 中配置了以下规则:
location /api {
proxy_pass http://localhost:8080;
}
这适用于 GET 请求,但不适用于 POST 或 PUT。对客户端的第一个响应是状态代码为 301 的响应:永久移动并且根据 HTTP spec 客户端应将 HTTP 方法更改为 GET 或 HEAD。客户端在第一次响应后自动更改方法,如 /var/log/nginx/access.log:
的 nginx 日志文件中所示
192.168.0.1 - - [14/Oct/2020:11:23:56 +0100] "POST /api/users?key=key HTTP/1.1" 301 162 "-" "PostmanRuntime/7.26.5"
192.168.0.1 - - [14/Oct/2020:11:23:56 +0100] "GET /api/users?key=key HTTP/1.1" 200 93 "http://server/api/users?key=key" "PostmanRuntime/7.26.5"
192.168.0.1 - - [14/Oct/2020:11:23:59 +0100] "PUT /api/users/1/deleted?key=key&deleted=false HTTP/1.1" 301 162 "-" "PostmanRuntime/7.26.5"
192.168.0.1 - - [14/Oct/2020:11:23:59 +0100] "GET /api/users/1/deleted?key=key&deleted=false HTTP/1.1" 405 141 "http://server/api/users/1/deleted?key=key&deleted=false" "PostmanRuntime/7.26.5"
来自 PUT 请求的 GET 请求失败并显示 405,因为路径“/api/users/{id}/deleted”没有映射的 GET。我尝试在“location /api {..}”中添加和修改许多不同的配置,例如:
location /api {
proxy_pass http://localhost:8080;
proxy_redirect http://localhost:8080/ /; # I tried "../api /", ".../api/ /", ".../ /api"
proxy_read_timeout 60s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
建议在 serverfault(how do I get nginx to forward HTTP POST requests via rewrite?)
我在 trac.nginx.com 上发现了完全相同的问题,但该配置也不起作用:
location /api { # "/api" and "/api/" doesn't work
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
我目前完全不知道我还应该尝试让它工作什么。
--- 编辑:在@ti7 和@ampularius 的帮助下,现在的工作解决方案是:
NGINX 位置条目:
location /api {
proxy_pass http://localhost:8080;
proxy_redirect off;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
}
并且在 Spring 引导服务的 application.properties 中没有进行任何更改,因此 NONE 这些设置对这种情况有任何作用:
server.use-forward-headers=true
server.forward-headers-strategy=native
server.forward-headers-strategy=framework
server.forward-headers-strategy=none
这可能是因为您的后端服务器认为请求是 http 并将其重定向到 https。尝试将此添加到您的位置块中:
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
它让您的后端服务器知道请求实际上是通过 https 发出的,但 tls 会进一步终止(在大多数情况下,您必须将代理服务器列入白名单才能使其正常工作)。
根据 this answer 你可以在 application.properties 中这样做:
server.use-forward-headers=true
最近我一直在与优秀的 Gunicorn WSGI server 和 nginx 前端打交道。
deploy docs建议禁用proxy_redirect
与proxy_pass
和Host
header设置,这可能是您麻烦的根源!
这在处理 POST
和 GET
请求方面效果很好,尽管使用的是 wildly-different 网络服务器。
location @proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
proxy_pass http://app_server;
}
我有一台安装了 nginx 的服务器(ubuntu 20.04 内核)。在同一台服务器上,我在端口 8080 上有一个 运行 Spring Boot Web(2.3.3.RELEASE) 服务。
我想从 Spring 外部引导 Web 服务访问资源 例如http:///server/api/users 访问 http://localhost/api/users 和 return 对客户端的响应。
我在 nginx 中配置了以下规则:
location /api {
proxy_pass http://localhost:8080;
}
这适用于 GET 请求,但不适用于 POST 或 PUT。对客户端的第一个响应是状态代码为 301 的响应:永久移动并且根据 HTTP spec 客户端应将 HTTP 方法更改为 GET 或 HEAD。客户端在第一次响应后自动更改方法,如 /var/log/nginx/access.log:
的 nginx 日志文件中所示192.168.0.1 - - [14/Oct/2020:11:23:56 +0100] "POST /api/users?key=key HTTP/1.1" 301 162 "-" "PostmanRuntime/7.26.5"
192.168.0.1 - - [14/Oct/2020:11:23:56 +0100] "GET /api/users?key=key HTTP/1.1" 200 93 "http://server/api/users?key=key" "PostmanRuntime/7.26.5"
192.168.0.1 - - [14/Oct/2020:11:23:59 +0100] "PUT /api/users/1/deleted?key=key&deleted=false HTTP/1.1" 301 162 "-" "PostmanRuntime/7.26.5"
192.168.0.1 - - [14/Oct/2020:11:23:59 +0100] "GET /api/users/1/deleted?key=key&deleted=false HTTP/1.1" 405 141 "http://server/api/users/1/deleted?key=key&deleted=false" "PostmanRuntime/7.26.5"
来自 PUT 请求的 GET 请求失败并显示 405,因为路径“/api/users/{id}/deleted”没有映射的 GET。我尝试在“location /api {..}”中添加和修改许多不同的配置,例如:
location /api {
proxy_pass http://localhost:8080;
proxy_redirect http://localhost:8080/ /; # I tried "../api /", ".../api/ /", ".../ /api"
proxy_read_timeout 60s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
建议在 serverfault(how do I get nginx to forward HTTP POST requests via rewrite?)
我在 trac.nginx.com 上发现了完全相同的问题,但该配置也不起作用:
location /api { # "/api" and "/api/" doesn't work
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
我目前完全不知道我还应该尝试让它工作什么。
--- 编辑:在@ti7 和@ampularius 的帮助下,现在的工作解决方案是:
NGINX 位置条目:
location /api {
proxy_pass http://localhost:8080;
proxy_redirect off;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
}
并且在 Spring 引导服务的 application.properties 中没有进行任何更改,因此 NONE 这些设置对这种情况有任何作用:
server.use-forward-headers=true
server.forward-headers-strategy=native
server.forward-headers-strategy=framework
server.forward-headers-strategy=none
这可能是因为您的后端服务器认为请求是 http 并将其重定向到 https。尝试将此添加到您的位置块中:
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
它让您的后端服务器知道请求实际上是通过 https 发出的,但 tls 会进一步终止(在大多数情况下,您必须将代理服务器列入白名单才能使其正常工作)。
根据 this answer 你可以在 application.properties 中这样做:
server.use-forward-headers=true
最近我一直在与优秀的 Gunicorn WSGI server 和 nginx 前端打交道。
deploy docs建议禁用proxy_redirect
与proxy_pass
和Host
header设置,这可能是您麻烦的根源!
这在处理 POST
和 GET
请求方面效果很好,尽管使用的是 wildly-different 网络服务器。
location @proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
proxy_pass http://app_server;
}