Bereitstellen mehrerer Proxy-Endpunkte unter Nginx

13

Ich habe ein paar API-Endpunkte, die ich unter einem einzigen Standort /apimit Unterpfaden zu verschiedenen Endpunkten bereitstellen möchte. Insbesondere möchte ich, dass webdis unter /apiund eine proprietäre API unter verfügbar sind /api/mypath.

Ich mache mir keine Sorgen über Konflikte mit der webdis-API, da ich Unterpfade verwende, bei denen es unwahrscheinlich ist, dass sie mit den Namen von Redis-Befehlen in Konflikt geraten. Außerdem habe ich die volle Kontrolle über das Design der API, um Konflikte zu vermeiden.

Hier ist die Konfigurationsdatei von meinem Testserver, auf den ich gehackt habe:

server {
  listen 80;
  server_name localhost;
  server_name 192.168.3.90;
  server_name 127.0.0.1;

  location / {
    root /home/me/src/phoenix/ui;
    index index.html;
  }

  # temporary hardcoded workaround
  location = /api/mypath/about {
    proxy_pass http://localhost:3936/v1/about;
  }

  location /api {
    rewrite ^/api/(.*)$ /$1 break;
    proxy_pass http://localhost:7379/;
  }

  # tried this but it gives "not found" error
  #location ^~ /api/mypath/ {
  #  rewrite ^/api/mypath/(.*)$ /$1 break;
  #  proxy_pass http://localhost:3936/v1/;
  #}
  #
  #location ^~ /api {
  #  rewrite ^/api/(.*)$ /$1 break;
  #  proxy_pass http://localhost:7379/;
  #}
}

Wie kann ich meine Problemumgehung so ändern, dass alle Anforderungen an /api/mypath/*den Endpunkt an Port 3936 und alle anderen an Port 7379 gesendet werden?

hamstar
quelle
Was meinst du damit tried this to no avail? Was ist passiert, als Sie diese Standortanweisung aktiviert haben? Verbindungszeitüberschreitung? Standort stimmt nicht überein?
Masegaloeh
Ah, danke für die Eingabeaufforderung, es wird ein nicht gefundener Fehler angezeigt. Bei weiteren Untersuchungen scheint es, dass ein Fehler von meiner API kommt, sodass er funktioniert! : D Aber die Umschreiberegel ist offensichtlich nicht, weil ich v1 zur URL hinzufügen muss ( localhost / api / mypath / v1 / about ) ... :(
hamstar

Antworten:

23

Sie müssen dafür nicht umschreiben.

server {
  ...

  location ^~ /api/ {
    proxy_pass http://localhost:7379/;
  }
  location ^~ /api/mypath/ {
    proxy_pass http://localhost:3936/v1/;
  }
}

Laut der Nginx-Dokumentation

Eine Position kann entweder durch eine Präfixzeichenfolge oder durch einen regulären Ausdruck definiert werden. Reguläre Ausdrücke werden mit dem vorangehenden ~*Modifikator (bei Übereinstimmung ohne Berücksichtigung der Groß- / Kleinschreibung) oder dem ~Modifikator (bei Übereinstimmung ohne Berücksichtigung der Groß- / Kleinschreibung) angegeben. Um einen Ort zu finden, der mit einer bestimmten Anfrage übereinstimmt, überprüft nginx zuerst Orte, die mit den Präfix-Zeichenfolgen (Präfix-Orten) definiert wurden. Unter diesen wird der Ort mit dem längsten übereinstimmenden Präfix ausgewählt und gespeichert. Dann werden reguläre Ausdrücke in der Reihenfolge ihres Auftretens in der Konfigurationsdatei überprüft. Die Suche nach regulären Ausdrücken wird beim ersten Treffer abgebrochen und die entsprechende Konfiguration verwendet. Wird keine Übereinstimmung mit einem regulären Ausdruck gefunden, wird die Konfiguration des zuvor gespeicherten Präfix-Speicherorts verwendet.

Wenn die am längsten übereinstimmende Präfixposition den ^~Modifikator hat, werden reguläre Ausdrücke nicht überprüft.

Daher wird jede Anfrage, die mit beginnt /api/mypath/, immer vom zweiten Block bedient, da dies die am längsten übereinstimmende Präfixposition ist.

Jede Anforderung, die mit /api/nicht unmittelbar gefolgt von beginnt, mypath/wird immer vom ersten Block bedient, da der zweite Block nicht übereinstimmt, wodurch der erste Block zum am längsten übereinstimmenden Präfixstandort wird.

Alexey Ten
quelle
2
Wenn Sie an dem Standort Modifikatoren aussehen ( =, ~*, ~und ^~) es scheinen mag kontraintuitiv , dass ^~schließt reguläres Ausdrücken (da ~gibt einen regulären Ausdruck) ... aber wenn Sie sich erinnern, ^in einer Regex Zeichenklasse (zB [^a-z]) negiert , dass Klasse (so dass das Beispiel bedeutet (jedes Zeichen außer denen von az); in ähnlicher Weise ^~negiert alle potenziellen regulären Ausdruckslokalisierungsblöcke.
Doktor J
6

OK, ich dachte, der Fehler "nicht gefunden" kommt von nginx, aber eigentlich von meiner API. Dies ist meine Lösung, wenn jemand interessiert ist:

server {
  listen 80;
  server_name localhost;
  server_name 192.168.3.90;
  server_name 127.0.0.1;

  location / {
    root /home/me/src/phoenix/ui;
    index index.html;
  }

  # automatically go to v1 of the (grape) API
  location ^~ /api/mypath/ {
    rewrite ^/api/mypath/(.*)$ /v1/$1 break;
    proxy_pass http://localhost:3936/;
  }

  location ^~ /api {
    rewrite ^/api/(.*)$ /$1 break;
    proxy_pass http://localhost:7379/;
  }
}
hamstar
quelle