Nginx https rewrite wandelt POST in GET um

17

Mein Proxy-Server läuft auf IP A und so greifen die Leute auf meinen Webdienst zu. Die Nginx-Konfiguration wird auf eine virtuelle Maschine auf IP B umgeleitet.

Für den Proxyserver auf IP A habe ich diesen in meinen Sites zur Verfügung gestellt

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;
        }
}

Das proxy_redirectwurde aus genommen wie bekomme ich Nginx HTTP POST - Anfragen über Rewrite weiterleiten?

Alles, was die öffentliche IP trifft, wird wegen des Umschreibens 443 treffen. Intern leiten wir auf der virtuellen Maschine auf 80 weiter.

Aber wenn ich ein Python-Skript wie das folgende ausführe, um unsere Konfiguration zu testen

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

Ich bekomme eine 405 Method Not Allowed. In nginx stellten wir fest, dass der interne Nginx beim Aufrufen des internen Servers eine GETAnfrage erhielt, obwohl wir im ursprünglichen Header eine Anfrage gestellt hatten POST(dies wurde im Python-Skript angezeigt).

Es scheint also, als hätte das Umschreiben ein Problem. Irgendeine Idee, wie man das behebt? Als ich die Umschreibung auskommentierte, traf sie mit Sicherheit 80 und ging durch. Da rewrite mit unserem internen Server kommunizieren konnte, ist rewrite selbst kein Problem. Es ist nur die Umschreibung, POSTauf die verwiesen wird GET.

Vielen Dank!

(Dies wird auch im Nginx-Forum gefragt, da dies ein kritischer Blocker ist ...)

CppLearner
quelle

Antworten:

8

Es ist nicht Nginx, es ist dein Browser.

Anmerkung aus RFC2616:

RFC 1945 und RFC 2068 geben an, dass der Client die Methode für die umgeleitete Anforderung nicht ändern darf. Die meisten vorhandenen Benutzeragentenimplementierungen behandeln 302 jedoch so, als wäre es eine 303-Antwort, die ein GET für den Standort ausführt [..]

Dies gilt für alle gängigen Browser und Sie können nichts dagegen tun.

c2h5oh
quelle
@ c2h50h Ich verstehe, dass die HTTP-Spezifikation so etwas ähnliches angibt. Aber was kann ich in Nginx machen? Ich meine , das eine triviale Setup, wo die Menschen vorwärts 443 an einen internen 80 - Port, aber sie noch tun können PUT, POST, DELETE, GET. In meinem vorherigen Setup hatte ich keinen zusätzlichen Proxy an der Front, der der Menge diente. Ich hatte dieselbe Konfiguration auf demselben internen Server (unserem Testserver). Das funktioniert gut.
CppLearner
Nichts. Es ist 100% Client-Seite. Wenn ein Webserver, ein beliebiger Webserver, eine 301- oder 302-Umleitung zurückgibt, ersetzt der Browser auf der Clientseite jede Art von Anforderung an GET. Keine serverseitige Konfiguration oder zurückgegebene HTTP-Header ändern dies nicht. Es ist aus historischen Gründen so (frühe Browser verhielten sich aufgrund von Missverständnissen so und es wurde ein De-facto-Standard).
c2h5oh
Zum einen ist dies kein richtiger Browser. Nun, man kann sagen, es ist ein Browser, weil er das HTTP-Protokoll verwendet. Okay. Das ist in Ordnung. Aber andererseits sieht es so aus, als ob dies nur passiert, wenn ich über diese zweischichtige Konfiguration mache. Wenn ich die gleiche Konfiguration direkt auf dem internen Computer installieren und den Test dort ausführen würde, würde ich mich nicht beschweren. Aber wie machen es die Leute in ihrer Produktion? Ich würde annehmen, dass einige Leute ähnliche Dinge tun, 443 auf eine VM umkehren, auf der möglicherweise nur 80 ausgeführt wird. Wenn es eine bessere Praxis gibt, würde ich es gerne lernen und davon hören.
CppLearner
1
Mit Browser meine ich HTTP-Client und mit allen gängigen Clients POSTwird es, GETwenn es 301 oder 302 umgeleitet wird. POST bleibt POST bei der Proxy-Umleitung, jedoch nicht beim Umschreiben.
c2h5oh
1
Nochmals 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.Die meisten Browser werden also eine Warnmeldung anzeigen, da ich für andere HTTP-Clients nicht einmal erraten kann, wie sie sich verhalten werden.
c2h5oh
1

Ich habe festgestellt, POST /api/branddass in verwandelt wurde, GET /api/brandweil die von mir verwendete Webanwendung ( flask-restful) eine "ungültige" Anfrage gestellt hat. Wenn ich es benutzt habe POST /api/brand/(beachte das Nachziehen /), war es erfolgreich.

gaozhidf
quelle
Ich habe Postman verwendet, um die Anmeldung für "django rest-auth" zu testen, und das gleiche Problem wurde beschrieben. Der Schlüssel war, dass ich das abschließende '/' in der POST-Anfrage vernachlässigt hatte.
Steve L