Nginx无法用rewrite实现多语言自动识别,因其不解析Accept-Language头;正确方案是:1. 在http块用map映射语言码生成$lang变量;2. 用location = /配合return 302 /$lang/跳转;3. 各语言路径由独立location处理。

直接用 rewrite 实现多语言自动识别并不可行——Nginx 的 rewrite 指令本身不解析 Accept-Language 请求头,也不能在匹配过程中动态提取语言偏好。它只做 URI 字符串改写,不具备 HTTP 头分析能力。真正可行的方案是:用 map 提取语言标识,再结合 return(非 rewrite)完成根路径跳转。下面分三步讲清楚关键配置和常见误区。
必须用 map 提前映射语言码,不能靠 rewrite 判断
map 是唯一能在 Nginx 中基于请求头生成变量的机制。它必须定义在 http 块顶层,不能放在 server 或 location 内。例如:
-
~*zh-cn|zh-sg|zh-hans zh;把常见简体中文标识统一映射为zh -
~*zh-tw|zh-hk zh-hant;将繁体中文归为zh-hant -
default en;确保无匹配时有兜底值
这个 $lang 变量后续才能被 return 或 proxy_pass 引用。而 rewrite 指令无法读取或计算该变量用于条件跳转。
根路径跳转必须用 return,不是 rewrite
在 server 块中捕获访问 / 的请求,应使用:
-
location = / { return 302 /$lang/; }—— 这是最简洁、语义最明确的方式 - 不要写成
rewrite ^/$ /$lang/ permanent;,因为rewrite在这里无法展开$lang(它只在server或location级生效,且不支持在正则替换中引用map变量) - 302 更适合调试;确认无误后可改为 301
各语言子路径需独立 location + alias 或 proxy_pass
跳转后的 /zh/、/en/ 等路径,要由对应 location 块处理:
- 静态站点推荐用
alias:如location /zh/ { alias /var/www/site/zh/; } - 动态服务可用
proxy_pass:如location /en/ { proxy_pass http://backend-en/; }(注意末尾斜杠) - 避免用
root+index,否则容易因路径拼接出错导致 404
rewrite 不适合此场景的三个原因
很多人尝试用 if ($http_accept_language ~* zh) 配合 rewrite,但这是危险且低效的做法:
-
if在location外不合法,在location内又受限于执行顺序,极易引发意外重定向循环 -
if性能较差,且不支持嵌套正则或复杂逻辑 -
rewrite的permanent或redirect标志虽能跳转,但无法动态构造目标路径(比如把zh-CN转成/zh/),必须依赖map预先转换


















