Nginx https重写将POST转换为GET


17

我的代理服务器在ip A上运行,这是人们访问我的Web服务的方式。Nginx配置将重定向到IP B上的虚拟机。

对于IP A上的代理服务器,我在我的站点中有此服务器

server {
        listen 443;
        ssl on;
        ssl_certificate nginx.pem;
        ssl_certificate_key nginx.key;

        client_max_body_size 200M;
        server_name localhost 127.0.0.1;
        server_name_in_redirect off;

        location / {
                proxy_pass http://10.10.0.59:80;
                proxy_redirect http://10.10.0.59:80/ /;

                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

}

server {
        listen 80;
        rewrite     ^(.*)   https://$http_host$1 permanent;
        server_name localhost 127.0.0.1;
        server_name_in_redirect off;
        location / {
                proxy_pass http://10.10.0.59:80;
                proxy_redirect http://10.10.0.59:80/ /;
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

proxy_redirect是取自我如何才能nginx的通过重写转发HTTP POST请求?

由于重写,影响公共IP的所有内容都将达到443。在内部,我们将转发到虚拟机上的80。

但是当我运行下面的python脚本来测试我们的配置时

import requests

data = {'username': '....', 'password': '.....'}
url = 'http://IP_A/api/service/signup'

res  = requests.post(url, data=data, verify=False)
print res
print res.json
print res.status_code
print res.headers

我得到一个405 Method Not Allowed。在nginx中,我们发现当它到达内部服务器时,内部nginx正在获取一个GET请求,即使在原始标头中我们执行了一个请求POST(这在Python脚本中也已显示)。

因此,似乎重写有问题。任何想法如何解决这个问题?当我注释掉重写时,它肯定会达到80,并且通过了。由于重写能够与我们的内部服务器通信,因此重写本身没有问题。只是将重写重写POSTGET

谢谢!

(这也会在Nginx论坛上询问,因为这是严重的阻止因素...)

Answers:


8

不是Nginx,而是您的浏览器。

RFC2616的注释:

RFC 1945和RFC 2068指定不允许客户端更改重定向请求的方法。但是,大多数现有的用户代理实现将302视为303响应,在位置[..]上执行GET。

所有流行的浏览器都是如此,您对此无能为力。


@ c2h50h我知道HTTP规范声明了类似的内容。但是我可以在Nginx中做什么?我的意思是,这是一个简单的设置,其中人民前进443到内部80口,但他们仍然可以做PUTPOSTDELETEGET。在我之前的设置中,我没有在前端为人群提供额外的代理。我在同一台内部服务器(我们的测试服务器)上具有相同的配置。很好
CppLearner 2012年

没有。这是100%的客户端。如果任何网络服务器返回301或302重定向,则客户端的浏览器将替换对的任何类型的请求GET。没有服务器端配置或返回的任何HTTP标头都不会改变它。就像出于历史原因(早期的浏览器由于误解而采取了这种行为,并成为事实上的标准)。
c2h5oh 2012年

好吧,这并不是一个真正的浏览器。好吧,您可以说这是浏览器,因为它使用HTTP协议。好吧。但是话又说回来,这似乎只有在我对两层配置进行操作时才会发生。如果我将相同的配置直接放在内部计算机上并在其中运行测试,它将不会抱怨。但是话又说回来,人们如何在生产中做到这一点?我假设某些人正在做类似的事情,将443反转为可能仅运行80的某些VM。如果有更好的做法,我想学习并了解它。
CppLearner 2012年

1
通过浏览器,我的意思是,如果重定向了301或302,则HTTP客户端以及所有流行的客户端POST都将变为GET。POST将在代理重定向时保持POST,但在重写时不保留。
c2h5oh 2012年

1
再次使用RFC2616:If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.因此,大多数浏览器都会弹出警告消息,对于其他HTTP客户端,我什至无法猜测其行为。
c2h5oh 2012年

1

我发现这POST /api/brandGET /api/brand因为我使用的Web应用程序(flask-restful)发出了“无效”请求。如果我使用了POST /api/brand/(请注意结尾处/),则表示成功。


我正在使用Postman测试django rest-auth登录,并且看到了描述的相同问题。关键是我在POST请求中忽略了结尾的“ /”。
史蒂夫·L
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.