Évitez les parameters de requête de décodage nginx sur proxy_pass (équivalent à AllowEncodedSlashes NoDecode)

J’utilise nginx comme équilibreur de charge devant plusieurs modèles. Dans mes demandes entrantes, j’ai des parameters de requête encodés. Mais lorsque la demande arrive à tomcat, les parameters sont décodés:

demande entrante à nginx:

curl -i "http://server/1.1/json/T;cID=1234;pID=1200;rF=http%3A%2F%2Fwww.google.com%2F" 

demande entrante à tomcat:

 curl -i "http://server/1.1/json/T;cID=1234;pID=1200;rF=http:/www.google.com/" 

Je ne souhaite pas que mes parameters de demande soient transformés car, dans ce cas, mon tomcat génère une erreur 405.

Ma configuration nginx est la suivante:

 upstream tracking { server front-01.server.com:8080; server front-02.server.com:8080; server front-03.server.com:8080; server front-04.server.com:8080; } server { listen 80; server_name tracking.server.com; access_log /var/log/nginx/tracking-access.log; error_log /var/log/nginx/tracking-error.log; location / { proxy_pass http://tracking/webapp; } } 

Dans ma configuration actuelle d’équilibreur de charge apache, j’ai la directive AllowEncodedSlashes qui conserve mes parameters codés:

 AllowEncodedSlashes NoDecode 

Je dois passer d’Apache à Nginx.

Ma question est tout à fait à l’opposé de cette question: évitez les parameters de requête d’échappement nginx sur proxy_pass

J’ai finalement trouvé la solution: je dois passer le paramètre $request_uri :

 location / { proxy_pass http://tracking/webapp$request_uri; } 

De cette manière, les caractères encodés dans la requête d’origine ne seront pas décodés, c.-à-d. Qu’ils seront transmis tels quels au serveur mandaté.

La réponse de Jean est bonne, mais elle ne fonctionne pas avec les sous-localisations. Dans ce cas, la réponse la plus générique est:

 location /path/ { if ($request_uri ~* "/path/(.*)") { proxy_pass http://tracking/webapp/$1; } } 

Il existe une option documentée pour la directive Nginx proxy_pass

S’il est nécessaire de transmettre l’URI sous la forme non traitée, alors la directive proxy_pass doit être utilisée sans partie d’URI :

 location /some/path/ { proxy_pass http://127.0.0.1; } 

donc dans votre cas, ça pourrait être comme ça. Ne vous inquiétez pas de la requête URI, elle sera transmise aux serveurs en amont

 location / { proxy_pass http://tracking; } 

J’espère que cela aide.

Notez que le décodage d’URL, communément appelé $uri “normalisation” dans la documentation de nginx, a lieu avant le serveur principal IFF:

  • soit tout URI est spécifié dans proxy_pass lui-même, même si ce n’est que la barre oblique tout seul,

  • ou, l’URI est modifié pendant le traitement, par exemple par rewrite .


Les deux conditions sont explicitement documentées à l’ adresse http://nginx.org/r/proxy_pass (c’est moi qui souligne):

  • Si la directive proxy_pass est spécifiée avec un URI , lorsqu’une requête est transmise au serveur, la partie d’un URI de requête normalisé correspondant à l’emplacement est remplacée par un URI spécifié dans la directive.

  • Si proxy_pass est spécifié sans URI , l’ URI de la demande est transmis au serveur sous la même forme que celle envoyée par un client lorsque la demande d’origine est traitée ou que l’URI complet de la demande normalisée est transmis lors du traitement de l’ URI modifié.


La solution dépend de la nécessité ou non de modifier l’URL entre le serveur frontal et le serveur principal.

  • Si aucun changement d’URI n’est requirejs:

     # map `/foo` to `/foo`: location /foo { proxy_pass http://localhost:8080; # no URI -- not even just a slash } 
  • Sinon, si vous devez permuter ou mapper /api du front-end avec /app sur le backend, vous pouvez obtenir l’URI d’origine de la variable $request_uri , et utiliser les directives de rewrite sur la variable $uri similaire à un DFA (BTW, si vous voulez rewrite action DFA, jetez un coup d’œil à mdoc.su ). Notez que la partie return 400 est nécessaire au cas où quelqu’un essaierait de contourner votre seconde règle de réécriture, car elle ne correspondrait pas à //api/ .

     # map `/api` to `/app`: location /foo { rewrite ^ $request_uri; # get original URI rewrite ^/api(/.*) /app$1 break; # drop /api, put /app return 400; # if the second rewrite won't match proxy_pass http://localhost:8080$uri; } 
  • Si vous voulez simplement append un préfixe pour le backend, vous pouvez simplement utiliser la variable $request_uri tout de suite:

     # add `/webapp` to the backend: location / { proxy_pass http://localhost:8080/webapp$request_uri; } 

Vous voudrez peut-être aussi jeter un coup d’œil à une réponse connexe , qui montre des tests du code similaires à ceux ci-dessus.

Dans certains cas, le problème ne se trouve pas du côté de nginx: vous devez définir le codage uri sur le connecteur Tomcat sur UTF-8.