Nginx-Proxy nach Anforderungsmethode

17

Ist es möglich / wie kann ich einen Nginx-Standortblock so konfigurieren, dass er je nach Anforderungsmethode (z. B. GET / POST) für verschiedene Backends Proxy-Funktionen verwendet?

Der Grund dafür ist, dass ich momentan die 2 Methoden unter 2 verschiedenen URLs (eine über http-Proxy und die andere über fcgi) bearbeite und versuche, es "REST" -voller zu machen, damit die GETting-Ressource die Liste im Idealfall zurückgibt Wenn Sie einen POST an dieselbe Ressource senden, sollte dies zur Liste hinzugefügt werden.

Brenton Alker
quelle

Antworten:

27

Ich verwende diese Konfiguration nicht, aber basierend auf den Beispielen hier :

location /service  {
  if ($request_method = POST ) {
    fastcgi_pass 127.0.0.1:1234;
  }

  if ($request_method = GET ) {
     alias /path/to/files;
  }
}

Wenn Sie Ihre eigene Anwendung schreiben, können Sie auch GET / POST darin prüfen und X-Accel-Redirect- Header senden , um den Transport der Dateien an nginx weiterzuleiten.

Jason
quelle
Der GET-Block ist in meinem Fall ein proxy_pass, aber ansonsten funktioniert das. Im Moment verwende ich nicht den zweiten if-Block. Nginx scheint die "Verarbeitung" zu stoppen, wenn die Direktive fastcgi_pass erreicht ist (dh nicht durchzufallen und auch den Proxy-Pass auszuführen), weil ich möchte, dass etwas anderes als POST zurückgesetzt wird an den Proxy.
Brenton Alker
2
Beachten Sie, dass ifdurch die im Allgemeinen Nginx Dokumentation wird abgeraten: nginx.com/resources/wiki/start/topics/depth/ifisevil
VOG
1
Also, was ist die Alternative?
WM
1
Siehe @WM meine Antwort: serverfault.com/a/823053/175421
VOG
@vog, Interessant. Ziemlich kluge Art und Weise, es zu tun. Danke für das Teilen.
WM
23

Obwohl Sie dies mit erreichen könnten if, wird dies in der Nginx-Dokumentation im Allgemeinen ifnicht empfohlen , da es mit anderen Anweisungen nicht gut funktioniert. Angenommen, GET sollte für alle Benutzer geöffnet sein, während POST nur für authentifizierte Benutzer mit HTTP Basic Auth gilt. Das müsste ifmit kombiniert werden auth_basic, was nicht richtig funktioniert.

Hier ist eine Alternative, die ohne geht if. Der Trick besteht darin, "GET" und "POST" als Teil der Upstream-Namen zu verwenden, damit diese durch Variablensubstitution behoben werden können:

http {
  upstream other_GET {
    server ...;
  }
  upstream other_POST {
    server ...;
  }
  server {
    location /service {
      proxy_pass http://other_$request_method;
    }
  }
}

Um dies mit HTTP Basic Auth für alles außer GET zu kombinieren, fügen Sie einfach einen limit_exceptBlock hinzu:

  ...
    location /service {
      proxy_pass http://other_$request_method;
      limit_except GET {
        auth_basic ...;
      }
    }
  ...
vog
quelle
Das Problem bei diesem Ansatz ist nun, dass wir 502 gateway errorwegen no resolver defined to resolve other_HEAD(oder was auch immer Ihr fehlender Upstream ist) zurückkehren werden. Es wird semantischer sein, so etwas zurückzugeben 405 method not allowed. Gibt es eine Möglichkeit, dies zu erreichen?
James
1
@ James: Dies sollte vielleicht als eine neue Frage formuliert werden, die sich auf diese bezieht. Ich habe keine Antwort auf dieses Detail, aber vielleicht auch andere.
VOG
0

Dies ist, was ich getan habe, um Dinge für mich arbeiten zu lassen

add_header Allow "GET, POST, HEAD" always;
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
    proxy_pass http://back-end;
}
Mansur Ali
quelle
Wie genau wechselt das zwischen zwei Endpunkten basierend auf der Anforderungsmethode?
Basic
0

Leichte Änderung der Antwort von vog, um einen Standard-Handler für andere Methoden wie OPTIONEN, PUT usw. einzuschließen.

    upstream webdav_default {
            server example.com;
    }
    upstream webdav_upload {
            server example.com:8081;
    }
    upstream webdav_download {
            server example.com:8082;
    }
    server {
            map upstream_location $request_method {
                    GET     webdav_download;
                    HEAD    webdav_download;
                    PUT     webdav_upload;
                    LOCK    webdav_upload;
                    default webdav_default;
            }
            location / {
                    proxy_pass https://$upstream_location;
            }
    }
timmmmmy
quelle
0

Ich konnte nicht die Antwort von @timmmmmy an der Arbeit, aber es weist mich auf die Karte Dokumentation und dies ist für mich:

map $request_method $upstream_location {
   PUT     example.com:8081;
   POST    example.com:8081;
   PATCH   example.com:8081;
   default example.com:8082;
}
server {
   location / {
      proxy_pass https://$upstream_location;
   }
}
rik harris
quelle