Nginx处理中文URL重写需按编码后字符串匹配,location须适配%XX格式路径,rewrite中应使用$args正则捕获编码参数,避免直接写中文或依赖不稳定的$arg_*变量解码。

在 Nginx 中处理带中文参数的 URL 重写,核心在于正确理解 URI 编码、location 匹配逻辑以及 rewrite 指令对变量的处理方式。中文字符在 URL 中默认会被浏览器编码为 UTF-8 的百分号格式(如“你好” → %E4%BD%A0%E5%A5%BD),Nginx 默认按原始编码后的字符串匹配和操作,**不自动解码**。因此,直接在 rewrite 中写中文或依赖未解码的 $args 容易失败。
确保 location 能匹配编码后的中文路径
Nginx 的 location 块匹配的是请求行中的原始 URI(已由客户端编码,但未被 Nginx 解码)。所以如果你的 URL 是:
/search?keyword=%E4%BD%A0%E5%A5%BD
或路径中含中文:
/文章/123.html → 实际请求可能是 /%E6%96%87%E7%AB%A0/123.html
那么 location 必须按编码后形式写,或使用正则匹配通用模式:
- 避免用
location /文章/—— 这不会匹配编码后的路径 - 改用正则:
location ~ ^/[^/]+/\d+\.html$或更稳妥地匹配编码段:location ~ ^/[\w%\-]+/\d+\.html$ - 对查询参数中的中文,
location本身不关心$args,所以通常用location /search即可,后续靠if或rewrite处理参数
用 if + rewrite 处理含中文参数的跳转(推荐)
当需要根据中文关键词重写时,可在 location 内用 if 判断 $args,再用 rewrite 构造新 URL。注意:$args 是原始编码字符串,可直接参与匹配:
location /search {
if ($args ~* "keyword=([^&]+)") {
set $kw $1;
# $kw 就是编码后的中文,如 %E4%BD%A0%E5%A5%BD
rewrite ^/search$ /s/$kw? redirect;
}
}这样会把 /search?keyword=你好 → 重定向到 /s/%E4%BD%A0%E5%A5%BD(保持编码)。如果目标后端能处理编码参数,这就足够了。
若需在重写中**解码后再用**(例如生成可读路径),Nginx 本身无内置 decode 函数,但可通过以下方式间接实现:
- 用 Lua 模块(OpenResty):
ngx.decode_args()或ngx.unescape_uri() - 让后端服务承担解码(更常见且可靠)——Nginx 只负责路由,不解码
避免常见陷阱
以下写法容易出错,需特别注意:
-
不要在 rewrite 正则中直接写中文:如
rewrite ^/文章/(.*)$ /post/$1;—— 因为实际 URI 是编码后的,匹配必然失败 -
不要依赖 $arg_keyword 解码值:Nginx 的内置变量
$arg_*是自动解码后的字符串(仅限简单 ASCII 和部分 UTF-8),但行为不稳定,尤其在高版本中可能因安全策略返回空;建议统一用$args配合正则捕获 -
开启 unescape_uri(不推荐):某些老教程提
rewrite ... last unescape_uri;,但该标志仅影响重写后的 URI 是否被再次编码,且不适用于参数提取,容易引发双重编码问题
实用示例:搜索关键词转静态路径
需求:将 /search?keyword=nginx教程 重写为 /search/nginx%E6%95%99%E7%A8%8B(保持编码),供前端或后端统一处理:
location = /search {
if ($args ~* "keyword=([^&]*)") {
set $encoded_kw $1;
rewrite ^(.*)$ /search/$encoded_kw? permanent;
}
# fallback:无 keyword 时返回 400
return 400;
}访问 /search?keyword=nginx教程 → 301 跳转到 /search/nginx%E6%95%99%E7%A8%8B。后端收到该路径后,自行 decodeURIComponent 即可还原中文。


















