nginx rewrite指令作用于已自动解码的utf-8请求uri(如/文章/简介),正则应直接匹配明文字符;重写结果在redirect/permanent时由nginx自动按rfc 3986编码,内部跳转(last/break)不编码。

Nginx 的 rewrite 指令本身不参与 URL 编码或解码操作,它只对已解码后的请求 URI(即 Nginx 内部处理的“干净路径”)进行正则匹配和字符串替换。多语言字符(如中文、日文、阿拉伯文等)在传输过程中必须经过 URL 编码(如 %E4%BD%A0 表示“你”),而 Nginx 在收到请求后会自动将其解码为 UTF-8 字符串,再交给 rewrite 模块处理。
URI 解码发生在 rewrite 之前
Nginx 在解析请求行时,会将原始请求中的百分号编码(Percent-encoded)自动解码为 Unicode 字符(前提是客户端发送的是合法 UTF-8 编码)。这意味着:
- 你在
rewrite规则中写的正则表达式,应直接面向解码后的路径,比如^/文章/(.*)$可匹配/文章/简介; - 若原始请求是
/%E6%96%87%E7%AB%A0/%E7%AE%80%E4%BB%8B,Nginx 自动转为/文章/简介后才进入 rewrite 匹配流程; - 因此无需在 regex 中写
%E6%96%87这类编码形式,否则无法匹配。
重写结果是否自动编码?
rewrite 输出的 replacement 字符串,如果包含非 ASCII 字符(如 /新页面/你好),Nginx 在生成 301/302 响应头时,会按 RFC 3986 要求重新编码为百分号格式(例如 /新页面/%E4%BD%A0%E5%A5%BD)。这个过程由 Nginx 自动完成,无需手动干预。
但注意:仅当使用 redirect 或 permanent 标志时才会触发响应头编码;若用 last 或 break,属于内部跳转,不涉及 HTTP 响应,也就没有编码输出问题。
常见陷阱与建议
实际配置中容易出错的地方:
-
避免在 regex 中混用编码与明文:不要写
^/%E6%96%87(.*)$,这几乎不可能匹配成功;应统一用解码后语义,如^/文章(.*)$; -
确保后端能正确接收 UTF-8 路径:Nginx 解码后传给 FastCGI 或 proxy_pass 的路径默认是 UTF-8,但需确认 PHP/Python 等后端未二次错误解码(例如 PHP 的
$_SERVER['REQUEST_URI']是原始编码串,而PATH_INFO是已解码的); -
location 块对多字节字符的匹配是安全的:Nginx 的正则引擎(PCRE)支持 UTF-8 模式,只要编译时启用了
--with-pcre-jit和 UTF-8 支持,中文路径匹配无异常; -
调试时开启 rewrite_log:
rewrite_log on;并配合error_log /path/to/error.log notice;,可查看 rewrite 实际匹配的是解码后的哪段路径。
一个实用示例:中文路径重定向
把访问 /产品/手机 的请求永久跳转到 /zh/products/smartphone:
location ~ ^/产品/手机$ {
return 301 /zh/products/smartphone;
}
或用 rewrite:
rewrite ^/产品/手机$ /zh/products/smartphone permanent;
这两者都基于已解码路径工作,浏览器最终收到的 Location 响应头会是:Location: /zh/products/smartphone(无编码),因为目标路径全是 ASCII;如果目标含中文,比如 /中文版/首页,Nginx 会自动编码为 /%E4%B8%AD%E6%96%87%E7%89%88/%E9%A6%96%E9%A1%B5 发送给客户端。











