我的基本目标是使用 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;
}
(请注意,所有这些指令现在都存在于服务器上下文中,没有任何位置块。)