I'm trying to do a "different path for different locale" config for nginx but ran into some strange situation here. See my config file here:
map $http_accept_language $locale {
default "en-US";
~*en "en-US";
~*zh "zh-CN";
}
server {
listen 80;
server_name _;
location / {
rewrite_log on;
rewrite ^/(.*)$ /prerendered/$locale/$1;
}
location /prerendered/en-US {
root /usr/share/nginx/html;
# try_files $uri $uri/ $uri.html /prerendered/en-US/index.html =404;
}
location /prerendered/zh-CN {
root /usr/share/nginx/html;
# try_files $uri $uri/ $uri.html /prerendered/zh-CN/index.html =404;
}
}
So what I want with this config is that based on different locale (default to en-US), nginx should rewrite the url internally to different path and return different files. However, the result I get is this:
file tree:
/usr/share/nginx/html/prerendered
├── en-US content:
│ ├── a.html a en-US
│ └── index.html index en-US
└── zh-CN
├── a.html a en-US
└── index.html index zh-CN
curl commands:
$ curl http://127.0.0.1/a.html
a en-US
$ curl http://127.0.0.1/a.html -H 'Accept-Language: en'
index en-US
$ curl http://127.0.0.1/a.html -H 'Accept-Language:zh'
index zh-CN
nginx's log:
2020/09/09 09:45:16 [notice] 29#29: *4 "^/(.*)$" matches "/a.html", client: 172.17.0.1, server: _, request: "GET /a.html HTTP/1.1", host: "127.0.0.1"
2020/09/09 09:45:16 [notice] 29#29: *4 rewritten data: "/prerendered/en-US/", args: "", client: 172.17.0.1, server: _, request: "GET /a.html HTTP/1.1", host: "127.0.0.1"
From Nginx's log, the "a.html" was matched, but for some reason missing in the rewritten data if "Accept-Language" header was provided. Am I doing anything wrong here?
The numeric captures are overwritten by the latest regular expression to be evaluated. The value of $locale is evaluated after the regular expression in the rewrite statement and because the map contains regular expressions, the value of $1 is reset to an empty string.
The usual solution is to use named captures, for example:
rewrite ^/(?<myuri>.*)$ /prerendered/$locale/$myuri last;
You could use the predefined variable $uri instead, but remember that it already contains a leading /, for example:
rewrite ^ /prerendered/$locale$uri last;
However, you do not need to use rewrite, the same function can be achieved with try_files, for example:
root /usr/share/nginx/html;
location / {
try_files $uri $uri/ /prerendered/$locale$uri =404;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With