我定义了这个
.htaccess
文件:
RewriteEngine On
# Disable http
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Disable www.
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
# /random run random.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
# Redirect /index.html in URL to /
RewriteRule (.*)index\.html$ /$1 [R=301,L]
# Redirect xxx.html in URL to nach xxx
RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
RewriteRule ^ /%1 [NC,L,R]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [NC,L]
我有这个文件夹结构:
index.html
about.html
example
(目录)
index.html
x.html
它适用于:
x.com
x.com/about
返回 /about.html
x.com/about.html
重定向至x.com/about
x.com/example/x
返回 /example/x.html
x.com/example/
返回 /example/index.html
但是这种情况也会发生,我想禁止这种情况:
x.com/example
重定向至x.com/example/
x.com/example
应返回 /example/index.html
您知道我必须在
.htaccess
文件中更改哪些内容吗?
重定向至x.com/example
x.com/example/
由于
/example
是一个物理目录,mod_dir “修复”URL 并在尾部斜杠后面附加 301(永久)重定向。尾部斜杠是 required 以便从该目录提供 DirectoryIndex
(即本例中的 index.html
)。
但是,我们可以使用
DirectorySlash Off
指令阻止 mod_dir 附加尾部斜杠。但是,我们必须发出内部重写以附加尾部斜杠,否则将无法提供 DirectoryIndex
文档(如上所述)。 (或者,我们可以直接重写索引文档。)
设置
DirectorySlash Off
时,我们还必须确保禁用目录列表(mod_autoindex),因为该目录中存在索引文档将不再阻止目录列表。
为了解决潜在的规范化问题,您现在需要向另一个方向“重定向”,以删除所请求 URL 上的任何尾部斜杠。例如。发送至
/example/
的请求现在需要重定向回 /example
。
此外,以下重写对应
.html
文件的规则并不严格正确:
RewriteCond %{REQUEST_FILENAME}.html -f RewriteRule ^ %{REQUEST_URI}.html [NC,L]
条件(使用
REQUEST_FILENAME
)不一定测试您最终在替换(使用REQUEST_URI
)中重写的相同URL。因此,在某些情况下(例如,当请求目录中不存在的文件时,该文件也恰好映射到 .html
文件),您可能会遇到重写循环(500 内部服务器错误)。请参阅以下关于 ServerFault 的问题/答案,其中更详细地介绍了这一点:https://serverfault.com/questions/989333/using-apache-rewrite-rules-in-htaccess-to-remove-html-causing-a -500-错误
这同样适用于之前附加
.php
扩展名的规则。
将以上几点综合起来,我们得到以下结论:
# [NEW] Directory listing (mod_autoindex) must be disabled
Options -Indexes
# [NEW] Prevent mod_dir appending the trailing slash
DirectorySlash Off
RewriteEngine On
# Disable http
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Disable www.
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
# Redirect /index.html in URL to /
RewriteRule (.*)index\.html$ /$1 [R=301,L]
# Redirect xxx.html in URL to just xxx
RewriteCond %{THE_REQUEST} /([^.?]+)\.html [NC]
RewriteRule ^ /%1 [R=301,L]
# [NEW] Redirect to remove trailing slash on direct requests
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.+)/$ /$1 [R=301,L]
# [NEW] Internal rewrite to append trailing slash to directories
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule (.+) $1/ [L]
# /random run random.php
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^\.]+)$ $1.php [L]
# Append ".html" if corresponding file exists
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f
RewriteRule ^ %{REQUEST_URI}.html [L]
与您当前问题相关的新规则用
[NEW]
表示。
在测试之前,您需要清除浏览器缓存,因为附加尾部斜杠的 301(永久)重定向将被缓存。使用 302(临时)重定向进行测试以避免潜在的缓存问题。
补充说明:
在测试同一请求加上
.php
does 映射到文件之前,测试请求是否未映射到文件是没有意义的,这些是互斥的事件,特别是因为您的 RewriteRule
pattern 不包括点(因此排除带有文件扩展名的 URL),所以我删除了该 条件。
无需反斜杠转义
RewriteCond
TestString 中的文字点,因为这是一个“普通”字符串,而不是正则表达式。
两个
NC
指令上不需要 RewriteRule
标志,因为正则表达式已经匹配 a-z 和 A-Z。
我在内部重写之前对规范重定向进行了分组。
# Redirect xxx.html in URL to nach xxx
RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
RewriteRule ^ /%1 [NC,L,R]
请注意,我还修改了此规则的 condition 中的正则表达式,以避免匹配潜在的查询字符串,否则 /foo.html?bar.html
形式的请求将导致双重重定向,并且查询字符串将被损坏。注意:您目前没有针对
.php
请求的相应规则。 (您可以在同一规则中处理两者。)