I use nginx as a load balencer in front of several tomcats. In my incoming requests, I have encoded query parameters. But when the request arrives to tomcat, parameters are decoded :
incoming request to nginx:
curl -i "http://server/1.1/json/T;cID=1234;pID=1200;rF=http%3A%2F%2Fwww.google.com%2F"
incoming request to tomcat:
curl -i "http://server/1.1/json/T;cID=1234;pID=1200;rF=http:/www.google.com/"
I don't want my request parameters to be transformed, because in that case my tomcat throws a 405 error.
My nginx configuration is the following :
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;
}
}
In my current apache load balancer configuration, I have the AllowEncodedSlashes directive that preserves my encoded parameters:
AllowEncodedSlashes NoDecode
I need to move from apache to nginx.
My question is quite the opposite from this question : Avoid nginx escaping query parameters on proxy_pass
Jean's answer is good, but it does not work with sublocations. In that case, the more generic answer is:
I finally found the solution: I need to pass
$request_uri
parameter :That way, characters that were encoded in the original request will not be decoded, i.e. will be passed as-is to the proxied server.
Note that URL decoding, commonly known as
$uri
"normalisation" within the documentation of nginx, happens before the backend IFF:either any URI is specified within
proxy_pass
itself, even if just the trailing slash all by itself,or, URI is changed during the processing, e.g., through
rewrite
.Both conditions are explicitly documented at http://nginx.org/r/proxy_pass (emphasis mine):
The solution depends on whether or not you need to change the URL between the front-end and the backend.
If no URI change is required:
Otherwise, if you do need to swap or map
/api
of the front-end with/app
on the backend, then you can get the original URI from the$request_uri
variable, and the use therewrite
directives over the$uri
variable similar to a DFA (BTW, if you want morerewrite
DFA action, take a look at mdoc.su). Note that thereturn 400
part is needed in case someone tries to get around your second rewrite rule, as it wouldn't match something like//api/
.If you simply want to add a prefix for the backend, then you can just use the
$request_uri
variable right away:You might also want to take a look at a related answer, which shows some test-runs of the code similar to the above.
In some cases, the problem is not on the nginx side - you must set the uri encoding on Tomcat connector to UTF-8.
There is one documented option for Nginx proxy_pass directive
so in your case it could be like this. Do not worry about request URI it will be passed over to upstream servers
Hope it helps.