¿Cómo se pueden reenviar los parámetros de la cadena de consulta a través de un proxy_pass con nginx?

114
upstream apache {
   server 127.0.0.1:8080;
}
server{
   location ~* ^/service/(.*)$ {
      proxy_pass http://apache/$1;
      proxy_redirect off;
   }
 }

El fragmento anterior redirigirá las solicitudes en las que la URL incluya la cadena "servicio" a otro servidor, pero no incluye parámetros de consulta.

Alex Luya
fuente

Respuestas:

163

De la documentación de proxy_pass :

Un caso especial es el uso de variables en la declaración proxy_pass: la URL solicitada no se utiliza y usted es totalmente responsable de construir la URL de destino usted mismo.

Dado que está usando $ 1 en el objetivo, nginx confía en que usted le diga exactamente qué pasar. Puede solucionar este problema de dos formas. Primero, eliminar el comienzo de la uri con un proxy_pass es trivial:

location /service/ {
  # Note the trailing slash on the proxy_pass.
  # It tells nginx to replace /service/ with / when passing the request.
  proxy_pass http://apache/;
}

O si desea utilizar la ubicación de expresiones regulares, solo incluya los argumentos:

location ~* ^/service/(.*) {
  proxy_pass http://apache/$1$is_args$args;
}
Kolbyjack
fuente
1
No creo que puedas hacer lo último. Lo intenté y nginx se quejó.
duma
3
¿Cómo se quejó? Lo probé en nginx 1.3.4 y funcionó bien para mí.
kolbyjack
Humm ... No puedo recordar ahora :( Pero siento que podría haber estado relacionado con el "~ *". Sin embargo, acabo de verificar y tengo nginx 1.2.3 (a través de homebrew). ¿Quizás eso es todo?
duma
"proxy_redirect default" no puede usarse con la directiva "proxy_pass" con variables
Jean-Philippe Caruana
1
tengo que usar la reescritura location /service/ { rewrite ^\/service\/(.*) /$1 break; proxy_pass http://apache; }
Andrew Arnautov
27

Utilizo una versión ligeramente modificada del segundo enfoque de kolbyjack con en ~lugar de ~*.

location ~ ^/service/ {
  proxy_pass http://apache/$uri$is_args$args;
}
Sebastián vom Meer
fuente
10

Modifiqué el código @kolbyjack para que funcione.

http://website1/service
http://website1/service/

con parámetros

location ~ ^/service/?(.*) {
    return 301 http://service_url/$1$is_args$args;
}
Pranav Garg
fuente
1
Tenga en cuenta que esto hará que el servidor devuelva una respuesta 301 al cliente antes de redirigir. La proxy_passdirectiva anterior hace la redirección en el lado del servidor.
Luke Peterson
1
Esto se interrumpirá si sus parámetros de consulta contienen caracteres codificados en URL (%). En su lugar, use la respuesta de Andrew.
David Weber
9

tienes que usar reescribir para pasar parámetros usando proxy_pass aquí hay un ejemplo que hice para la implementación de la aplicación angularjs en s3

El alojamiento de sitios web estáticos de S3 enruta todas las rutas a Index.html

adoptado a sus necesidades sería algo así como

location /service/ {
    rewrite ^\/service\/(.*) /$1 break;
    proxy_pass http://apache;
}

si quieres terminar en http://127.0.0.1:8080/query/params/

si quieres terminar en http://127.0.0.1:8080/service/query/params/ necesitarás algo como

location /service/ {
    rewrite ^\/(.*) /$1 break;
    proxy_pass http://apache;
}
Andrew Arnautov
fuente
1
¿Parece que maneja bien los parámetros de ruta ( /path/params) pero no los parámetros de consulta ( ?query=params)?
Will el
Ah no, mi error, los parámetros de consulta deberían agregarse automáticamente (están en mis pruebas).
Será el
2

github gist https://gist.github.com/anjia0532/da4a17f848468de5a374c860b17607e7

#set $token "?"; # deprecated

set $token ""; # declar token is ""(empty str) for original request without args,because $is_args concat any var will be `?`

if ($is_args) { # if the request has args update token to "&"
    set $token "&";
}

location /test {
    set $args "${args}${token}k1=v1&k2=v2"; # update original append custom params with $token
    # if no args $is_args is empty str,else it's "?"
    # http is scheme
    # service is upstream server
    #proxy_pass http://service/$uri$is_args$args; # deprecated remove `/`
    proxy_pass http://service$uri$is_args$args; # proxy pass
}

#http://localhost/test?foo=bar ==> http://service/test?foo=bar&k1=v1&k2=v2

#http://localhost/test/ ==> http://service/test?k1=v1&k2=v2
AnJia
fuente
1

Para redirigir sin cadena de consulta, agregue las siguientes líneas en el bloque del servidor debajo de la línea del puerto de escucha:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/;
}

Con cadena de consulta:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/?$query_string;
}
Abhishek
fuente
1
La documentación de nginx es explícita para evitar su uso ifcuando sea posible. En este caso, la solución podría ser correcta usando locationcomo se muestra en otras respuestas.
Andrés Morales
2
de todos modos, una solución más, incluso si tiene inconvenientes, es mejor
Dmitry Malugin