Servir plusieurs points de terminaison proxy sous emplacement dans Nginx

13

J'ai quelques points de terminaison d'API que je veux servir à partir d'un emplacement unique /apiavec des sous-chemins allant vers différents points de terminaison. Plus précisément, je veux que les webdis soient disponibles sur /apiet une API propriétaire disponible sur /api/mypath.

Je ne m'inquiète pas des conflits avec l'API webdis car j'utilise des sous-chemins qui ne risquent pas de se heurter aux noms de commandes redis, et j'ai également un contrôle total sur la conception de l'API pour éviter les conflits.

Voici le fichier de configuration de mon serveur de test sur lequel je pirate:

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

Comment puis-je modifier ma solution de contournement pour que toutes les demandes /api/mypath/*soient envoyées au point de terminaison sur le port 3936 et tout le reste sur le port 7379?

hamstar
la source
Qu'entendez-vous par tried this to no avail? Que s'est-il passé lorsque vous activez cette directive d'emplacement? Délai de connection dépassé? L'endroit ne correspond pas?
masegaloeh
Ah merci pour l'invite, il donne une erreur introuvable, à la suite d'une enquête plus approfondie, il semble que l'erreur provient de mon API, donc cela fonctionne! : D Mais la règle de réécriture n'est évidemment pas parce que je dois ajouter v1 à l'URL ( localhost / api / mypath / v1 / about ) ... :(
hamstar

Réponses:

24

Vous n'avez pas besoin de réécrire pour cela.

server {
  ...

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

Selon la documentation nginx

Un emplacement peut être défini soit par une chaîne de préfixe, soit par une expression régulière. Les expressions régulières sont spécifiées avec le ~*modificateur précédent (pour la correspondance insensible à la casse) ou le ~modificateur (pour la correspondance sensible à la casse). Pour trouver un emplacement correspondant à une demande donnée, nginx vérifie d'abord les emplacements définis à l'aide des chaînes de préfixe (emplacements de préfixe). Parmi eux, l'emplacement avec le préfixe correspondant le plus long est sélectionné et mémorisé. Les expressions régulières sont ensuite vérifiées, dans l'ordre de leur apparition dans le fichier de configuration. La recherche d'expressions régulières se termine à la première correspondance et la configuration correspondante est utilisée. Si aucune correspondance avec une expression régulière n'est trouvée, la configuration de l'emplacement du préfixe mémorisé précédemment est utilisée.

Si l'emplacement du préfixe correspondant le plus long a le ^~modificateur, les expressions régulières ne sont pas vérifiées.

Par conséquent, toute demande commençant par /api/mypath/sera toujours traitée par le deuxième bloc, car il s'agit de l' emplacement de préfixe correspondant le plus long .

Toute demande commençant par /api/non immédiatement suivie par mypath/sera toujours traitée par le premier bloc, car le deuxième bloc ne correspond pas, ce qui fait du premier bloc l' emplacement de préfixe correspondant le plus long .

Alexey Ten
la source
2
Si vous regardez les modificateurs de localisation ( =, ~*, ~et ^~) il peut sembler contre-intuitif qui ^~exclut les expressions régulières (car ~indique une correspondance d'expression régulière) ... Cependant, si vous vous souvenez, à l' ^intérieur d' une classe de caractères regex (par exemple [^a-z]) annule que classe (telle que l'exemple signifie (n'importe quel caractère sauf ceux de az); de même, ^~annule tout bloc de localisation d'expression régulière potentiel.
Doktor J
6

OK compris, je pensais que l'erreur "introuvable" provenait de nginx, mais en fait, elle provenait de mon API. C'est ma solution si quelqu'un est intéressé:

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
la source