NGINX正则Location重写语法问题:请求URI重写失败排查
你的问题出在rewrite规则中使用$request_uri导致生成了带有双斜杠的异常URI,进而引发后端返回406状态码。让我们一步步拆解并修复:
问题分析
你当前的rewrite规则是:
rewrite ^(.*)$ /app/$request_uri last;
$request_uri变量包含了完整的原始请求URI(包括开头的/和查询参数),所以当请求/proxy.stream?opt=1进来时,拼接后的URI会变成/app//proxy.stream?opt=1(/app/末尾的/加上$request_uri开头的/形成了双斜杠)。虽然NGINX通常会自动合并双斜杠,但这种异常路径可能导致后端服务器无法正确解析请求,或者触发了某些后端的内容校验逻辑,最终返回406(无法提供符合客户端Accept头的内容)。
另外,你的正则匹配^(.*)$其实没必要,因为已经通过location ~ ^/proxy.stream(.*)$限定了匹配范围,完全可以简化规则。
修复后的配置
把rewrite规则替换为以下任意一种即可:
方案1:精准拼接目标路径(推荐)
location ~ ^/proxy.stream(.*)$ { rewrite ^/proxy.stream(.*)$ /app/proxy.stream$1 last; }
这个规则会精准地把/proxy.stream?opt=1重写为/app/proxy.stream?opt=1,彻底避免双斜杠问题,同时完整保留所有查询参数。
方案2:利用$request_uri但规避双斜杠
location ~ ^/proxy.stream(.*)$ { rewrite ^/proxy.stream /app$request_uri last; }
这里去掉了/app/末尾的/,直接拼接$request_uri,生成的URI是/app/proxy.stream?opt=1,同样不会出现双斜杠问题。
方案3:跳过rewrite,直接在当前location代理
如果你不想用rewrite做内部重定向,也可以直接在正则location里配置proxy_pass,一步完成转发:
location ~ ^/proxy.stream(.*)$ { proxy_pass http://app_cluster/app/proxy.stream$1; }
NGINX会自动把原始查询参数附加到proxy_pass的URL后面,效果和rewrite完全一致。
验证修复
修改配置后,执行nginx -s reload重新加载配置,再测试请求http://10.1.2.15:9002/proxy.stream?opt=1,应该会被正确转发到后端的/app/proxy.stream?opt=1路径,不再返回406状态码。
内容的提问来源于stack exchange,提问作者Keith Bennett

