我有一个由.php文件组成的简单网站,没有数据库。我使用htaccess来执行以下规则:
- 强制HTTPS
- 在开始时强制www
- 删除.php扩展名(
https://www.example.com/page.php
-〉https://www.example.com/page
) - 无尾随斜杠
最后一条规则,没有尾随斜杠,不起作用。相反,它会导致错误404。这就是我试图解决的问题。如果有人打开https://www.example.com/page/
,我希望它重定向到https://www.example.com/page
,而不是给予404。
以下是我目前使用的.htaccess
相关代码,它基于html5的htaccess模板,并添加了复制粘贴片段,因为我对.htaccess
一无所知。
ErrorDocument 404 /errors/404.php
Options -MultiViews
<IfModule mod_rewrite.c>
# (1)
RewriteEngine On
# (2)
Options +FollowSymlinks
</IfModule>
# to https
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R] # to 301
</IfModule>
# force www at beginning
<IfModule mod_rewrite.c>
RewriteEngine On
# # (1)
RewriteCond %{HTTPS} =on
RewriteRule ^ - [E=PROTO:https]
RewriteCond %{HTTPS} !=on
RewriteRule ^ - [E=PROTO:http]
# # (2)
# # RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{SERVER_ADDR} !=127.0.0.1
RewriteCond %{SERVER_ADDR} !=::1
RewriteRule ^ %{ENV:PROTO}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R] # <- for test, for prod use [L,R=301]
</IfModule>
# remove .php
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
</IfModule>
# remove trailing /
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} (.*)/$
RewriteRule ^(.*)/$ $1 [L,R] # <- for test, for prod use [L,R=301]
</IfModule>
1条答案
按热度按时间0qx6xfy61#
这些规则的顺序是错误的。对
/page/
的请求首先被重写为/page/.php
(这自然会导致404)* 在 * 你删除尾部斜杠之前(它不再有尾部斜杠,因为它以.php
结尾)。然而,你的规则应该是检查请求是 not a directory,而不是 not a file。第二个检查
REQUEST_URI
的条件是多余的。你还缺少 substitution 字符串上的斜杠前缀(并且没有定义RewriteBase
),所以这将导致错误的重定向。但是,您的规则可以大大简化。不需要
<IfModule>
Package 器或多个RewriteEngine On
指令,并且当它始终是HTTPS时,非www到www重定向不必要地保留了方案(HTTP或HTTPS)。你的规则可以写得更简洁,像这样:
我想知道检查
SERVER_ADDR
的两个条件在这里是否真的有必要,因为在HTTP到HTTPS规则上没有类似的东西。在正则表达式字符类中使用时,不需要反斜杠转义文字点。
您标记为“remove.php”的规则实际上并没有“删除”任何东西。它在
.php
扩展名已经被删除的请求上 * 追加 *.php
扩展名。在尝试重写请求之前,最好先测试相应的.php
文件是否存在,而不是无条件地附加.php
,希望该文件存在(这在某些情况下可能导致意外错误,并且至少在.php
请求上记录404,而不是实际请求的URL)。此规则块如果请求HTTP + non-www,也会导致两次重定向,因为您首先将HTTP重定向到同一主机上的HTTPS。如果实现HSTS,这实际上是一个要求,但否则您可以通过反转前两个规则来避免这种双重重定向。(但是,删除尾部斜杠的重定向也会导致写入的额外重定向。如果需要,可以更改此重定向,但不会立即导致问题。)
注意:小心行尾注解(我已经删除了它们)。Apache不支持它们。它们可能看起来只是因为配置指令的解析方式而起作用,但是如果你省略了任何可选参数,那么你会得到一个500内部服务器错误,因为语法无效。(但是是的,总是先用302 - temporary - redirects测试。)
更新:
一切都像它应该的那样工作,除了这个:
example.com/nonexistingfile.php
。这导致了一个404,但奇怪的是,不是我的自定义404(ErrorDocument 404 /errors/404.php
),而是一个“服务器备份404”。只是一个纯文本“文件未找到”。对此有什么想法吗?这可能与PHP在服务器上的安装方式有关(与上面的指令无关)。有可能您的服务器最终将所有
.php
请求代理到后端PHP引擎,基本上绕过了.htaccess
/ErrorDocument指令。作为一种解决方法,你可以尝试使用mod_rewrite强制404,用于任何包含
.php
扩展名的请求(因为我假设没有客户端应该直接请求.php
文件)。例如,尝试在
RewriteEngine On
指令之后立即添加以下内容(或在“to https”规则之后添加,以确保404响应始终通过HTTPS):对
REDIRECT_STATUS
env var的检查确保此规则仅适用于来自客户端的直接请求,而不是在服务器上内部重写的请求(根据最后一条规则)。