Nginx处理路径特殊字符的核心是理解匹配基于解码后$uri、转发需保持原始编码:避免正则元字符冲突,禁用merge_slashes和ignore_invalid_headers,proxy_pass用无尾缀写法透传编码,静态资源优先前缀匹配+alias而非rewrite。

在 Nginx 的 location 块中处理路径中的特殊字符,核心不是“过滤”或“转义”,而是理解 Nginx 的匹配逻辑与 URI 解码时机——它匹配的是解码后的 $uri,但转发时需保持原始编码。处理不当会导致 400、404 或后端路径错乱(比如 %2F 被当成 / 引发目录穿越,%3A 冒号被还原导致 URL 截断)。
避免正则 location 中的元字符冲突
当文件名含 [、]、.、+、? 等字符时,它们在 URI 中通常已编码(如 [ 对应 [),但 Nginx 正则引擎匹配的是解码后的路径字符串。例如请求 /report_v1[draft].pdf,Nginx 实际匹配 /report_v1[draft].pdf。
- 若写
location ~ \.pdf$,没问题;但若用location ~ ^/.*\[.*\].pdf$,方括号必须转义为\[和\] - 更稳妥的做法是避开正则:用前缀匹配
location /report/+try_files,让文件系统或后端承担命名解析 - 对含竖线
|、冒号:等字符的路径,不要依赖rewrite拆分,改用map提前映射(如将/css/base|v2.css映射为/css/base-v2.css)
控制 proxy_pass 转发时的编码完整性
默认情况下,proxy_pass 会尝试“规范化”路径,自动解码再拼接,极易破坏合法编码。关键在于让原始编码完整抵达后端:
- 禁用隐式路径拼接:写成
location /api/ { proxy_pass http://backend; }(不带结尾斜杠),Nginx 会把/api/foo%2Bbar完整转发为http://backend/api/foo%2Bbar - 若需重写路径,用正则捕获并显式传递:
if ($request_uri ~ ^/api/(.*)$) { proxy_pass http://backend/$1; } - 绝对不要写
proxy_pass http://backend/api/;—— 这会触发自动解码+拼接,%2F变成/,%3A变成:,后端可能拒收或解析错误
关闭干扰性默认行为
某些全局配置会无意破坏含编码的请求,需在 http 或 server 块中统一关闭:
-
merge_slashes off;:防止连续斜杠//被压缩为单个/,保护%2F%2F类编码 -
ignore_invalid_headers off;:允许请求头(如Referer)含百分号编码,避免因含%被直接拒绝 -
server_name_in_redirect off;:防止重定向响应中 URL 被二次编码
静态文件场景下的安全落地方式
对于 CSS、PDF、图片等静态资源,路径含特殊字符时,优先绕过正则匹配和重写逻辑:
- 用
location /static/(前缀匹配)+alias或root,指向磁盘上不含特殊字符的真实路径(如把AK20210709%3A1d53ee...文件存为AK20210709_colon_1d53ee...) - 若必须保留原始 URL,配合
try_files和map做无损映射,而非rewrite—— rewrite 后的目标路径若含未编码字符,Nginx 可能再次编码或报错 - 对冒号
:、竖线|等高危字符,建议前端生成 URL 时使用更保守的编码方案(如全量 hex 编码),后端约定解码规则,Nginx 只做透传


















