使用 nginx 从 URL 中删除 index.html 和 .html

使用 nginx 从 URL 中删除 index.html 和 .html

我的基本目标是使用 nginx 提供以下干净的 URL:

  • /供应/index.html
  • /abc/供应/abc/index.html
  • /abc/def供应/abc/def.html
  • /abc重定向至/abc/

为了让每个资源都有规范的名称,我还想规范化任何带有多余文件名或扩展名的 URL:

  • /index.html重定向至/
  • /abc/index.html重定向至/abc/
  • /abc/def.html重定向至/abc/def

我认为可以实现这一目标的指令是:

index index.html;
try_files $uri.html $uri $uri/ =404;

# Redirect */index and */index.html to *.
rewrite ^(.*)/index(\.html)?$ $1 permanent;
# Redirect *.html to *.
rewrite ^(.+)\.html$          $1 permanent;

然而,结果却和我想象的不一样:

  • //index并且/index.html全部重定向到/(循环)。
  • /abc并且/abc/都重定向到/abc/(循环)。

(它按设计/abc/def.html和要求工作/abc/def;只有目录 URL 不起作用。)

我不确定这里发生了什么;也许我误解了它的rewrite工作原理?

(我已经尝试使用位置块,但这也会导致循环,因为try_files执行内部重定向到发送 HTTP 301 的位置块。)

编辑:从根本上说,我需要类似位置块的东西,它只与原始请求 URI 匹配,但为了内部重定向而被忽略,因此它不会与 try_files 指令结合创建循环。

答案1

你可能正在寻找类似的解决方案这里解释的一个

server {
    listen       80;
    server_name  mysite.com;

    index index.html;
    root /var/www/mysite/public;

    location / { 
        try_files $uri $uri/ @htmlext;
    }   

    location ~ \.html$ {
        try_files $uri =404;
    }   

    location @htmlext {
        rewrite ^(.*)$ $1.html last;
    }   
}

答案2

我相信我已经找到了解决方案,尽管我没有足够的经验来判断这是否会在特殊情况下发生故障或者是否可以通过其他方式更轻松地解决。

基本上,问题在于location ~ ... {}块不仅在原始请求 URI 上匹配,而且在try_files和其他重写的结果上也匹配。因此,如果我有一个位置块来通过重定向剥离 index.html 或 .html,那么它不仅会在客户端直接请求index.html或时运行abc.html,而且在客户端请求/abc并且服务器内部分别将它们重定向到/index.html和时也会运行abc.html,从而导致重定向循环。

但是,重定向模块提供了一个if可以检查$request_uri变量的指令 - 该变量不会因内部重定向而改变:

index index.html;
try_files $uri $uri.html $uri/ =404;

# like "location ~", but only for matching the original request. 
if ($request_uri ~ /index(.html)?$) {
  rewrite ^(.*/)index(.html)?$ $1 permanent;
}
if ($request_uri ~ \.html$) {
  rewrite ^(.*)\.html$ $1 permanent;
}

(请注意,所有这些指令现在都存在于服务器上下文中,没有任何位置块。)

相关内容