「Nginx」- 变量 $request uri 与 $uri 对比

  CREATED BY JENKINSBOT

问题描述

对于http://info.example.com/special/hotelbrand/honghe/地址,如果使用如下配置:

if ( $uri !~ ^/special/.* )
{
	rewrite ^(.*)$  https://www.example.com/zx/ permanent;
}

在配置中的正则表达式与地址匹配,根据if语句(不匹配则跳转),则页面不应该进行跳转。但是在实际运行过程中,页面被重定向,与预期不符。

原因分析

原因在于我们没有正确理解$request_uri变量与$uri变量。问题在于我们对很多地方的理解有误。

问题分析

随着问题深入调查,我们发现如下配置才会导致问题:

server
{
    listen 80;
    server_name info.example.com;

    if ( $uri !~ ^/special/.* )
    {
        rewrite ^(.*)$  https://www.example.com/zx/ permanent;
    }

    error_page 404 = /404.html;
}

也许老手已经看到问题所在了…………事情是这个样子的…………

首先,我们访问的连接不存在。根据error_page 404 = /404.html;配置,我们被“内部重定向”到404.html页面。所谓“内部重定向”是返回404.html页面内容,就好像客户端端在访问404.html页面,而不是让客户端浏览器重定向404.html页面。

但是…………当他内部重定向到404.html时,遇到if语句,而if语句中的$uri变量此时为/404.html值(因为$uri就是这个样子),然后客户端被重定向到在rewrite中定义的连接。

更进一步

如果理解上面的内容,你就能够理解为什么下面的配置会跳转到https://404.example.com地址:

server
{
    listen 80;
    server_name info.example.com;

    if ( $uri ~ /404.html )
    {
        rewrite ^(.*)$  https://404.example.com permanent;
    }

    if ( $uri !~ ^/special/.* )
    {
        rewrite ^(.*)$  https://www.example.com/zx/ permanent;
    }

    error_page 404 = /404.html;
}

解决办法

$uri变量替换为$request_uri变量(它是完整的原始请求URI值,不会发生变化)。

附加说明

request uri vs uri

$uri – 在请求中的当前URI,被“标准化”后的。所谓标准化是指,解码被编码的字体(以“%XX”形式),解析相对路径引用,将联系反斜线合并为壹个。在请求处理期间,变量$uri的值可能发生变化。比如进行内部重定向,或者使用索引文件。

$request_uri – 完整的原始请求URI(带有参数)

参考文献

NGINX $request_uri vs $uri
Module ngx_http_core_module/$uri
Module ngx_http_core_module/$request_uri
Module ngx_http_core_module/error_page