nginx中rewrite无法直接匹配带问号的url,因默认只匹配路径$uri;需用$request_uri精确匹配完整请求或$query_string单独处理参数,并注意转义问号、结尾加?清空参数及避免if与rewrite混用陷阱。

直接用 rewrite 匹配带问号的 URL 会失败,因为 Nginx 默认只匹配路径部分($uri),不包含查询参数(即问号及其后内容)。必须借助变量或条件判断来处理。
用 $request_uri 精确匹配完整请求路径
当需要针对特定含参数的 URL(如 /a.html?id=67)做跳转时,$request_uri 是最直接的方案。它保留原始请求中的路径和查询字符串,支持正则匹配。
- 写法示例:
if ($request_uri ~ "^/a\.html\?id=67$") {<br> rewrite ^/(.*)$ http://zt.epython.cn/20190320/b.html? permanent;<br>} - 注意反斜杠转义问号:
\?,否则会被当作正则量词解析 - 结尾加问号
?可清空跳转后携带的原查询参数,避免出现b.html?id=67
用 $query_string 单独判断查询参数
若只关心参数值(如所有 id=xxx 请求),用 $query_string 更灵活,它只提取问号后的参数部分。
- 写法示例:
if ($query_string ~ "^id=([0-9]+)$") {<br> set $id $1;<br> rewrite ^/product\.html$ /item/$id.html? permanent;<br>} - 支持捕获分组(如
$1),可用于构造新路径 - 同样需在 rewrite 目标末尾加
?,防止参数被自动拼接
避免常见陷阱
很多配置看似合理,实际无效,关键点在于理解 Nginx 的匹配机制:
-
rewrite ^/a.html?id=67$ ...—— 错误:Nginx 不把?id=67当作路径一部分,该规则永远不触发 - 漏掉
?导致参数透传 —— 如跳转后变成b.html?id=67,可能引发循环或逻辑错误 - 在
location块中混用if和rewrite时,优先级易混乱,建议统一放在server块顶层或独立location中 - 多个
rewrite规则顺序执行,但if内部的rewrite受其作用域限制,不会跳出
更简洁的替代方案:return + 正则捕获
对于简单跳转,return 比 rewrite 更轻量且语义清晰:
- 示例:
if ($request_uri ~ "^/old\.php\?page=(\w+)$") {<br> return 301 /new-page/$1;<br>} -
return直接返回状态码和目标 URL,不经过内部重写流程,性能略优 - 适用于 301/302 跳转场景,无需担心
last/break行为差异











