nginx在location匹配前自动对uri进行utf-8解码,故匹配基于解码后的字符串;需用curl发送%xx编码请求验证,避免未编码中文或正则缺u标志等陷阱。

直接用 curl 模拟不同编码格式的请求,配合 return 或 echo 指令观察响应,是最轻量、最可靠的测试方式。Nginx 本身在匹配前会自动对 URI 进行解码(即把 %E4%BD%A0 还原为“你”),所以真正参与 location 匹配的是解码后的字符串,而非原始编码字节。
用 curl 构造带中文编码的请求
确保请求中包含真实 URL 编码,而不是直接写中文字符:
-
curl -v "http://localhost/%E4%BD%A0%E5%A5%BD"→ 匹配解码后/你好 -
curl -v "http://localhost/%e4%bd%a0%e5%a5%bd"→ 小写编码,同样解码为/你好,Nginx 默认不区分大小写处理十六进制编码 -
curl -v "http://localhost/%u4F60%u597D"→%uXXXX是 IE 旧式编码,Nginx 不识别也不解码,会被当作普通路径字面量处理(如匹配location /%u4F60)
验证 location 是否按预期解码后匹配
在配置中加入带标识的 return,让响应体明确告诉你哪个 location 被命中:
location = /你好 {
return 200 "exact-utf8";
}
location ~ ^/[%A-Fa-f0-9]{6,} {
return 200 "hex-encoded-path";
}
location ~ ^/%[A-Fa-f0-9]{2}+ {
return 200 "raw-percent-encoded";
}
location / {
return 200 "fallback";
}
然后分别测试:
-
curl http://localhost/%E4%BD%A0%E5%A5%BD→ 返回exact-utf8,说明已解码并精确匹配 -
curl http://localhost/%E4%BD%A0/test→ 若未定义/你好/类似前缀规则,可能落入/或正则分支,看返回确认逻辑
检查浏览器实际发送的编码格式
不同浏览器对中文路径的编码行为略有差异:
- Chrome、Firefox、Edge:统一使用 UTF-8 编码 +
%XX格式(如“测试”→%E6%B5%8B%E8%AF%95) - Safari 在某些版本中可能对路径中非 ASCII 字符做额外转义,可用开发者工具的 Network 面板查看 Request URL 原始值
- 移动端 WebView 行为基本与对应内核一致,无需单独适配
只要 Nginx 配置能覆盖 UTF-8 编码的 %XX 序列(尤其是 2–3 字节常见组合),就可兼容所有现代客户端。
避免常见陷阱
以下情况会导致匹配失败,但和客户端无关,需主动排查:
- URI 中存在未编码的中文字符(如直接
/你好):Nginx 接收时可能因系统 locale 或 HTTP 协议限制被截断或乱码,必须要求客户端编码 - location 使用
~正则但未加u标志(PCRE 默认不支持 Unicode 字符类):应改用字节模式匹配,例如~ ^/%[A-Fa-f0-9]{6,}$判断是否为至少两个中文字符的编码 - proxy_pass 后端服务对路径再次解码:若后端也解码一次,可能导致重复解码(如
%E4%BD%A0→ “你” → 再解成乱码),建议后端关闭二次解码或统一用原始$request_uri











