Comment les paramètres de chaîne de requête peuvent-ils être transmis via un proxy_pass avec nginx?

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

L'extrait ci-dessus redirigera les demandes dont l'URL comprend la chaîne «service» vers un autre serveur, mais n'inclut pas les paramètres de requête.

Alex Luya
la source

Réponses:

163

À partir de la documentation proxy_pass :

Un cas particulier est l'utilisation de variables dans l'instruction proxy_pass: l'URL demandée n'est pas utilisée et vous êtes entièrement responsable de la construction de l'URL cible vous-même.

Puisque vous utilisez $ 1 dans la cible, nginx compte sur vous pour lui dire exactement quoi transmettre. Vous pouvez résoudre ce problème de deux manières. Tout d'abord, supprimer le début de l'URI avec un proxy_pass est 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/;
}

Ou si vous souhaitez utiliser l'emplacement de l'expression régulière, incluez simplement les arguments:

location ~* ^/service/(.*) {
  proxy_pass http://apache/$1$is_args$args;
}
kolbyjack
la source
1
Je ne crois pas que vous puissiez faire ce dernier. J'ai essayé et nginx s'est plaint à moi.
Douma
3
Plaints comment? Je viens de le tester sur nginx 1.3.4 et cela a bien fonctionné pour moi.
kolbyjack
Humm .. Je ne me souviens plus maintenant :( Mais j'ai l'impression que cela pourrait avoir été lié au "~ *". Cependant, je viens de vérifier, et j'ai nginx 1.2.3 (via homebrew). Peut-être que c'est ça?
duma
"proxy_redirect default" ne peut pas être utilisé avec la directive "proxy_pass" avec des variables
Jean-Philippe Caruana
1
doivent utiliser la réécriture location /service/ { rewrite ^\/service\/(.*) /$1 break; proxy_pass http://apache; }
Andrew Arnautov
27

J'utilise une version légèrement modifiée de la deuxième approche de kolbyjack avec ~au lieu de ~*.

location ~ ^/service/ {
  proxy_pass http://apache/$uri$is_args$args;
}
Sebastian vom Meer
la source
10

J'ai modifié le code @kolbyjack pour qu'il fonctionne pour

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

avec paramètres

location ~ ^/service/?(.*) {
    return 301 http://service_url/$1$is_args$args;
}
Pranav Garg
la source
1
Gardez à l'esprit que cela obligera le serveur à renvoyer une réponse 301 au client avant la redirection. La proxy_passdirective ci-dessus effectue la redirection côté serveur.
Luke Peterson
1
Cela ne fonctionnera pas si vos paramètres de requête contiennent des caractères encodés URL (%). Utilisez plutôt la réponse d'Andrew.
David Weber
9

vous devez utiliser la réécriture pour passer les paramètres à l'aide de proxy_pass voici un exemple que j'ai fait pour le déploiement de l'application angularjs vers s3

Hébergement de site Web statique S3 Route tous les chemins vers Index.html

adapté à vos besoins serait quelque chose comme

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

si vous voulez vous retrouver dans http://127.0.0.1:8080/query/params/

si vous voulez vous retrouver dans http://127.0.0.1:8080/service/query/params/ vous aurez besoin de quelque chose comme

location /service/ {
    rewrite ^\/(.*) /$1 break;
    proxy_pass http://apache;
}
Andrew Arnautov
la source
1
Cela semble bien gérer les paramètres de chemin ( /path/params) mais pas les paramètres de requête ( ?query=params)?
Volonté le
Ah non, mon erreur, les paramètres de requête doivent être ajoutés automatiquement (ils sont dans mes tests).
Volonté le
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
la source
1

Pour rediriger sans chaîne de requête, ajoutez les lignes ci-dessous dans le bloc Serveur sous la ligne de port d'écoute:

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

Avec la chaîne de requête:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/?$query_string;
}
Abhishek
la source
1
La documentation de nginx est explicite pour éviter de l'utiliser iflorsque cela est possible. Dans ce cas, la solution pourrait être correcte en utilisant locationcomme indiqué dans une autre réponse.
Andrés Morales
2
de toute façon une solution de plus même si elle a des inconvénients, c'est mieux
Dmitry Malugin