带有尾部斜杠的奇怪 Nginx 行为

Strange Nginx behavior with trailing slashes

我有一个非常有趣的行为。我想避免在我的网站上的 URL 中使用尾部斜杠。我已将 rewrite ^/(.*)/$ / permanent; 规则放入我的服务器块,所以
https://example.com/something/,
https://example.com/something////
重定向到
https://example.com/something;

https://example.com/
重定向到
https://example.com

但是https://example.com////被重定向到... https://enjoygifts.ru////(实际上不要重定向,它是200代码)。为什么?

这是我的服务器块:


    server {
        listen 443 ssl;
        ...
        ... ssl directives
        ...

        root        /var/www/mysite.com;
        index       index.php;
        server_name mysite.com;
        rewrite ^/(.*)/$ / permanent;

        location / {
            rewrite ^/.*$ /index.php last;
        }

        location ~ ^/index.php {
            try_files    $uri =404;
            include      /etc/nginx/fastcgi.conf;
            fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
        }

        location ~ ^/storage/app/uploads/public { try_files $uri 404; }
        ...
        ... lot of similar location blocks
        ...
    }

https://example.com 并不真正存在,根 URI 是 / - 它在浏览器地址栏中的显示方式取决于浏览器 - 有些会自动显示单独的 / 而其他人会删除一个孤零零的 /.

所以你不能从 https://example.com/ 重定向到 https://example.com - 它会被默默地解释为从 https://example.com/https://example.com/ 的重定向。

Nginx 在评估 locationrewrite 语句时使用 normalized URI,并生成 $uri 变量。多个连续出现的 / 折叠成单个 /.

虽然正则表达式 ^/(.*)/$ 与 URI // 匹配,但语句永远不会看到它。因为 Nginx 已经将该 URI 规范化为 /,这与正则表达式不匹配。


如果具有多个 / 的根 URI 有问题,请将正则表达式应用于 $request_uri 变量,该变量包含规范化之前的原始 URI,还包括查询字符串(如果有的话) ).

例如:

if ($request_uri ~ "^/{2,}(\?|$)") { 
    return 301 /$is_args$args; 
}

这可以放在您的 location / {...} 块内。请参阅 this caution 关于 if.

的用法