So entfernen Sie den Pfad mit einem Nginx-Proxy-Pass

77

Ich habe eine laufende Web-Anwendung auf http://example.com/und möchte eine andere Anwendung auf einem separaten Server "mounten" http://example.com/en. Upstream-Server und proxy_passscheinen zu funktionieren, aber für ein Problem:

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location /en {
    proxy_pass http://luscious;
  }
}

Beim Öffnen example.com/enkehrt meine vorgelagerte Anwendung zurück 404 not found /en. Dies ist sinnvoll, da der Upstream den Pfad nicht hat /en.

Ist proxy_pathdie richtige lösung Soll ich "upstream" umschreiben, damit es /enstattdessen als Root-Pfad abhört ? Oder gibt es eine Direktive, mit der ich den Pfad, der zum Upstream weitergeleitet wurde, umschreiben kann?

Berkes
quelle

Antworten:

133

Dies ist wahrscheinlich die effizienteste Methode, um das zu tun, was Sie möchten, ohne reguläre Ausdrücke zu verwenden:

location = /en {
    return 302 /en/;
}
location /en/ {
    proxy_pass http://luscious/;  # note the trailing slash here, it matters!
}
cnst
quelle
1
Soweit ich weiß, würde der letzte Teil immer noch "/ en" als Pfad zum Proxy übergeben, nicht wahr?
Berkes
15
@berkes, nein, das wird es nicht - der abschließende Schrägstrich proxy_passmacht den Unterschied. Außerdem ist diese Antwort korrekter als die, die Sie sich ausgedacht haben, da sie auch sicherstellt, dass sie erhalten proxy_redirectbleibt default, sodass Sie 302et al in Ihrem Backend weiterhin verwenden können und es überall korrekt funktioniert.
21.
4
Ah, mir fehlte der
abschließende
3
AAARGH! SCHRÄGSTRICH !
Barrymac
4
3 Stunden suchen und ja ... Es war der abschließende Schrägstrich. Danke Kumpel!
Lucas P.
12

Ich möchte auf eine neuere, auf Regex basierende Antwort eingehen, die immer beliebter wird.

location ~ ^/en(/?)(.*)$ {  # OOPS!
  proxy_pass http://luscious/$2$is_args$args;  # OOPS!
}

Die Lösung mag auf den ersten Blick niedlicher erscheinen, ist aber aus mehreren Gründen falsch.

  • Der obige reguläre Ausdruck würde einem Request-URL von entsprechen /enjoyund ihn auf den /joyUpstream umleiten . Ist das wirklich beabsichtigt?

  • Eine Anfrage nach /enführt nicht zu Weiterleitungen, die direkt /vom Upstream bereitgestellt werden (fast so, als wäre /en/stattdessen eine Anfrage nach gestellt worden, aber nicht ganz). Wenn Sie stromaufwärts relativ URIs innerhalb Ihrer Root - Seite verwenden (sonst, warum nicht haben Sie das /en/Präfix genau dort in dem Upstream - URIs?), ZB src="style.css"(die ein sprachspezifische Referenz könnten url("menu.png"), zum Beispiel), dann wird der Browser verlangt , dass als /style.cssstatt /en/style.css. (Oder auch wenn Sie überall absolute URIs verwenden, was ist, wenn jemand relativ auf eine undurchsichtige, semi-optionale Ressource verweist?)

  • Gemäß meinem früheren Rat bei einer anderen Frage, die bereits in der eigenen Antwort des OP erwähnt wurde , verhindert die Verwendung regulärer Ausdrücke, dass die proxy_redirectDirektive den Standardwert von defaulthat und offstattdessen auf " down to" zurückgesetzt wird. Dies bedeutet, dass, wenn der Upstream auf Location: http://127.0.0.1:8080/en/dir/eine Anfrage antwortet /en/dir, der Client dies sieht, was offensichtlich nicht richtig funktioniert. (Was besonders ironisch für eine /enAnfrage gewesen wäre, die die Verwendung von Regex in erster Linie auffordert, aber diese spezielle Implementierung leidet stattdessen an einem anderen Problem, wie oben bereits erwähnt.) Außerdem, wenn Sie bereits die verwendenupstreamWenn Sie nur versuchen, einen benutzerdefinierten Server zu verwenden, kann dies besonders hässlich werden. Dies gilt insbesondere dann, wenn Sie möglicherweise mehr als einen Upstream-Server haben. Wie haben Sie proxy_redirectfür jeden dieser Server einen eigenen ? Sie könnten reguläre Ausdrücke auch innerhalb von verwenden proxy_redirect, möglicherweise sogar, um mit einem beliebigen Host übereinzustimmen. Was ist dann, wenn Sie sich entscheiden, in Zukunft eine domänenübergreifende Umleitung durchzuführen?

Um zu versuchen, einige der oben genannten Punkte mit einem einzigen, auf Regex basierenden Speicherort zu lösen, können wir Folgendes tun (beachten Sie, dass proxy_passwir auch den Verweis auf einen Server aus einer auf Regex upstreambasierenden Direktive entfernen mussten, um dies proxy_redirecteinfacher zu gestalten):

location ~ ^/en/?((?<=/).*)?$ {
  location = /en { return 302 /en/; }
  proxy_pass http://127.0.0.1:8080/$1$is_args$args;
  proxy_redirect http://127.0.0.1:8080/ /en/;
}

Also, wenn Sie mich fragen, wäre die ursprüngliche Lösung mit den beiden Standorten auf der obersten Ebene der Geschwister immer noch eine bessere Idee, als sich selbst in ein Kaninchenbau zu graben, indem Sie stattdessen den Regex-Weg gehen.

cnst
quelle
Dies führt zu einer Ausnahme:nginx: [emerg] location "/en" is outside location "^/en/?((?<=/).*
Athlan
1
@Athlan, das liegt daran, dass du das eigentlich gar nicht verwenden solltest! Wenn Sie immer noch möchten, können Sie diesen Speicherort außerhalb des regulären Ausdrucks platzieren.
5.
localation = / en außerhalb zu setzen, funktioniert wirklich gut! danke
Sebastian Webber
7

Also habe ich die Antwort auf stackoverflow gefunden :

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location ~ ^/en(/?)(.*) {
    proxy_pass http://luscious/$2;
  }
}

Grundsätzlich gilt: Übergeben eines regulären Ausdrucks an den Speicherort und Weitergeben der Rückreferenz an die proxy_pass-URL.

Berkes
quelle
Ich denke "proxy_pass luscious / $ ;" sollte "proxy_pass luscious / $ 2 " sein
Zafer
1
@Zafer ist richtig, die obige Antwort gab mir einen Fehler
Franck
Ich habe die Antwort geändert, aber keinen Server zur Hand, auf dem ich das ausprobieren kann, Geldautomat, daher wird es nicht überprüft.
Berkes
0

Buchhaltung nach Nginx-Dokumenten

Um eine Anforderung an einen HTTP-Proxy-Server zu übergeben, wird die Anweisung proxy_pass innerhalb eines Speicherorts angegeben. Zum Beispiel:

location /some/path/ {
    proxy_pass http://www.example.com/link/;
}

Diese Beispielkonfiguration führt dazu, dass alle an diesem Speicherort verarbeiteten Anforderungen an den Proxy-Server an der angegebenen Adresse weitergeleitet werden. Diese Adresse kann als Domainname oder als IP-Adresse angegeben werden. Die Adresse kann auch einen Port enthalten:

location ~ \.php {
    proxy_pass http://127.0.0.1:8000;
}

Beachten Sie, dass im obigen ersten Beispiel auf die Adresse des Proxy-Servers der URI / link / folgt. Wenn der URI zusammen mit der Adresse angegeben wird, ersetzt er den Teil des Anforderungs-URI, der mit dem Standortparameter übereinstimmt. Beispielsweise wird hier die Anfrage mit dem URI /some/path/page.html an http://www.example.com/link/page.html weitergeleitet . Wenn die Adresse ohne URI angegeben wird oder es nicht möglich ist, den zu ersetzenden Teil des URI zu bestimmen, wird der vollständige Anforderungs-URI übergeben (möglicherweise geändert).

Jeff
quelle