Udostępnianie wielu punktów końcowych proxy w lokalizacji w Nginx

14

Mam kilka punktów końcowych interfejsu API, które chcę obsługiwać z jednego miejsca /apiz podścieżkami prowadzącymi do różnych punktów końcowych. W szczególności chcę, aby webdis był dostępny pod adresem /apii zastrzeżony interfejs API dostępny pod adresem /api/mypath.

Nie martwię się o kolizje z interfejsem API webdis, ponieważ używam ścieżek podrzędnych, które raczej nie kolidują z nazwami komend redis, a także mam pełną kontrolę nad projektem interfejsu API, aby uniknąć kolizji.

Oto plik konfiguracyjny z mojego serwera testowego, na którym hakowałem:

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

Jak mogę zmienić moje obejście, aby wszelkie żądania /api/mypath/*trafiały do ​​punktu końcowego w porcie 3936, a wszystko inne do portu 7379?

hamstar
źródło
Co masz na myśli tried this to no avail? Co się stało po włączeniu tej dyrektywy lokalizacji? Czas połączenia minął? Lokalizacja niezgodna?
masegaloeh
Ach, dziękuję za podpowiedź, daje błąd, który nie został znaleziony, przy dalszym badaniu wydaje się, że błąd pochodzi z mojego API, więc działa! : D Ale reguła przepisywania oczywiście nie jest, ponieważ muszę dodać v1 do adresu URL ( localhost / api / mypath / v1 / about ) ... :(
hamstar

Odpowiedzi:

24

Nie potrzebujesz do tego przepisywania.

server {
  ...

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

Zgodnie z dokumentacją nginx

Lokalizację można zdefiniować za pomocą ciągu przedrostka lub wyrażenia regularnego. Wyrażenia regularne są określane za pomocą poprzedniego ~*modyfikatora (w przypadku rozróżniania wielkości liter) lub ~modyfikatora (w przypadku rozróżniania wielkości liter ). Aby znaleźć lokalizację pasującą do danego żądania, nginx najpierw sprawdza lokalizacje zdefiniowane za pomocą ciągów prefiksów (lokalizacje prefiksów). Spośród nich wybrano i zapamiętano lokalizację z najdłuższym pasującym prefiksem. Następnie sprawdzane są wyrażenia regularne w kolejności ich pojawienia się w pliku konfiguracyjnym. Wyszukiwanie wyrażeń regularnych kończy się przy pierwszym dopasowaniu i używana jest odpowiednia konfiguracja. Jeśli nie zostanie znalezione dopasowanie do wyrażenia regularnego, zostanie użyta konfiguracja zapamiętanej wcześniej lokalizacji prefiksu.

Jeśli najdłużej pasująca lokalizacja prefiksu ma ^~modyfikator, wówczas wyrażenia regularne nie są sprawdzane.

Dlatego każde żądanie, które zaczyna się od, /api/mypath/będzie zawsze obsługiwane przez drugi blok, ponieważ jest to najdłużej pasująca lokalizacja prefiksu.

Każde żądanie, które zaczyna się /api/od, po którym nie następuje natychmiast, mypath/będzie zawsze obsługiwane przez pierwszy blok, ponieważ drugi blok nie pasuje, dlatego pierwszy blok jest najdłuższą pasującą lokalizacją prefiksu.

Alexey Ten
źródło
2
Jeśli spojrzeć na modyfikatorów lokalizacyjnych ( =, ~*, ~, i ^~) może się to wydawać sprzeczne z intuicją, że ^~nie obejmuje wyrażenia regularne (ponieważ ~wskazuje Dopasowanie wyrażenia regularnego) ... Jednak jeśli pamiętamy, ^wewnątrz klasy znaków (np regex [^a-z]) neguje , że klasa (taka, że ​​przykład oznacza (dowolny znak z wyjątkiem z az); podobnie, ^~neguje wszelkie potencjalne bloki lokalizacji wyrażeń regularnych.
Doktor J
6

OK się zorientowałem, myślałem, że błąd „nie znaleziono” pochodzi z nginx, ale tak naprawdę pochodzi z mojego API. To jest moje rozwiązanie, jeśli ktoś jest zainteresowany:

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
źródło