Sirviendo múltiples puntos finales proxy bajo ubicación en Nginx

13

Tengo un par de puntos finales API que quiero servir desde una sola ubicación /apicon subrutas que van a puntos finales diferentes. Específicamente, quiero que webdis esté disponible en /apiy una API patentada disponible en /api/mypath.

No me preocupan los conflictos con la API webdis porque estoy usando subrutas que es poco probable que entren en conflicto con los nombres de los comandos de redis, y también tengo control total sobre el diseño de la API para evitar conflictos.

Aquí está el archivo de configuración de mi servidor de prueba que he estado pirateando:

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

¿Cómo puedo cambiar mi solución para que cualquier solicitud /api/mypath/*vaya al punto final en el puerto 3936 y todo lo demás al puerto 7379?

hamstar
fuente
¿Qué quieres decir con tried this to no avail? ¿Qué pasó cuando habilitas esa directiva de ubicación? ¿El tiempo de conexión expiro? ¿Ubicación no coincidente?
masegaloeh
Ah, gracias por el mensaje, está dando un error no encontrado, en una investigación adicional parece que el error proviene de mi API, ¡así que está funcionando! : D Pero la regla de reescritura obviamente no es porque tengo que agregar v1 a la URL ( localhost / api / mypath / v1 / about ) ... :(
hamstar

Respuestas:

23

No necesita reescribir para esto.

server {
  ...

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

De acuerdo con la documentación de nginx

Una ubicación puede definirse mediante una cadena de prefijo o mediante una expresión regular. Las expresiones regulares se especifican con el ~*modificador anterior (para la coincidencia entre mayúsculas y minúsculas) o el ~modificador (para la coincidencia entre mayúsculas y minúsculas). Para encontrar una ubicación que coincida con una solicitud determinada, nginx primero verifica las ubicaciones definidas utilizando las cadenas de prefijo (ubicaciones de prefijo). Entre ellos, se selecciona y recuerda la ubicación con el prefijo coincidente más largo. Luego se verifican las expresiones regulares, en el orden de su aparición en el archivo de configuración. La búsqueda de expresiones regulares termina en la primera coincidencia y se utiliza la configuración correspondiente. Si no se encuentra ninguna coincidencia con una expresión regular, se utiliza la configuración de la ubicación del prefijo recordada anteriormente.

Si la ubicación de prefijo coincidente más larga tiene el ^~modificador, no se verifican las expresiones regulares.

Por lo tanto, cualquier solicitud que comience /api/mypath/siempre será atendida por el segundo bloque, ya que es la ubicación de prefijo más larga .

Cualquier solicitud que comience /api/sin un seguimiento inmediato mypath/siempre será atendida por el primer bloque, ya que el segundo bloque no coincide, por lo que el primer bloque es la ubicación de prefijo de coincidencia más larga .

Alexey Ten
fuente
2
Si nos fijamos en los modificadores de ubicación ( =, ~*, ~, y ^~) que pueda parecer contrario a la intuición de que ^~se excluyen las expresiones regulares (ya que ~indica una coincidencia de expresiones regulares) ... Sin embargo, si usted recuerda, ^dentro de una clase de caracteres de expresiones regulares (por ejemplo [^a-z]) niega que clase (de modo que el ejemplo significa (cualquier carácter excepto los de az); de manera similar, ^~niega cualquier posible bloque de ubicación de expresión regular.
Doktor J
6

OK lo descubrí, pensé que el error "no encontrado" provenía de nginx, pero en realidad provenía de mi API. Esta es mi solución si alguien está interesado:

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
fuente