我有一个由共享托管提供商托管的网站。它是带有 FPM/FastCGI 和 PHP 7.2 的 Apache
作为共享主机,我可以访问的唯一配置是 htaccess,但显然不是任何 Apache conf 文件。
我在 htaccess 中配置了一个自定义错误页面,如下所示:ErrorDocument 404 /error404.php
。今天我注意到我的自定义错误 404 页面没有显示。相反,File not found.
浏览器会返回纯文本,并在标头中显示状态代码 404。进一步调查显示,这种情况仅发生在请求文件。如果您请求不存在的目录然后你就会得到自定义错误页面!例如,请求mydomain.info/dummy.htm
给出错误,但请求mydomain.info/dummy/
返回自定义错误页面。
服务器正在记录每个错误AH01071
的错误。Primary script unknown
File not found.
看来服务器上启用了 ModSecurity,因为日志记录了恶意请求被拒绝,例如[client xxx.xxx.xxx.xxx] ModSecurity: Access denied with code 403 (phase 2). ... etc
另外,我最近按照托管服务提供商的建议改用了 PHP 7.2。但改回 5.6 并没有改变症状。
知道是什么原因造成的吗?我看到过一些信息,说也许ProxyPass
或者ProxyErrorOverride
可以解决问题,但我不知道在哪里设置。
为了记录,下面是完整的 htaccess,包括所有缺陷:
RewriteEngine on
# AddType TYPE/SUBTYPE EXTENSION
AddType audio/mpeg mp3
AddType video/mp4 mp4 m4v
# Add WWW
RewriteCond %{HTTP_HOST} ^mydomain\.info [NC]
RewriteRule ^(.*) https://www.mydomain.info/$1 [R=301,L,NE]
# Redirect for .COM
RewriteCond %{HTTP_HOST} mydomain\.com$ [NC]
RewriteRule ^/?(.*) https://www.mydomain.info/$1 [R=301,L,NE]
# Force HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
# Home page canonicalization
RewriteCond %{THE_REQUEST} ^.*\/index\.htm\ HTTP/
RewriteRule ^(.*)index\.htm$ /$1 [R=301,L,NE]
# Removed page_missing.htm
Redirect 301 /page_missing.htm /new_page.htm#section_b
# Some content moved to sub-folder
Redirect 301 /extra_content.htm /extra/extra_content.htm
# Internally redirect all HTM & HTML URLs to PHP
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)\.(htm|html)$ /$1\.php
# Error 404 page
ErrorDocument 404 /error404.php
<IfModule mod_expires.c>
# Activate mod_expires for this directory
ExpiresActive on
# Default
ExpiresDefault "access plus 7 days"
# Default for actual documents
ExpiresByType text/html "access plus 15 minutes"
# cache CSS files for 7 days
ExpiresByType text/css "access plus 7 days"
# locally cache common resource types for 7 days
ExpiresByType image/jpg "access plus 7 days"
ExpiresByType image/jpeg "access plus 7 days"
ExpiresByType image/gif "access plus 7 days"
ExpiresByType image/png "access plus 7 days"
ExpiresByType application/pdf "access plus 7 days"
ExpiresByType audio/mpeg "access plus 7 days"
</IfModule>
答案1
# Internally redirect all HTM & HTML URLs to PHP RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)\.(htm|html)$ /$1\.php
我并不一定会期望这会导致您遇到的问题,但是,您有指令“盲目地”将任何不存在的.htm
(或.html
)请求重写为等效.php
文件,无论该.php
文件是否存在。 (错误文档应该捕获丢失的文件,而不是最初请求的.php
丢失文件。).htm
这也可以解释您在请求不存在的“目录”(即形式的请求)时看到的行为差异/dummy/
,该请求不会被上述指令重写并且似乎按预期“工作”(即调用自定义错误文档)。
您可以修改上述规则,以便仅.php
在文件存在时才重写。例如:
# Internally redirect all HTM & HTML URLs to PHP
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.*)\.(htm|html)$ /$1.php [L]
无需对文字点进行转义RewriteRule
代换。您应该包含该L
标志(尽管它目前是最后一个 mod_rewrite 指令,因此严格来说并不重要)。
更新:如果您请求不存在的 php 页面,那么您仍然会收到“找不到文件”的响应。
这听起来像是服务器配置问题。您可以通过手动重写错误文档来“解决”此问题:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule \.php$ /error404.php [L]
尽管您可能需要进行修改error404.php
来解决这个问题。
或者... 我还想知道从 Apache 触发 404(从表面上看,这似乎没有太大意义)是否会改变此行为。例如,代替上面的重写:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule \.php$ - [R=404]
这种方法背后的想法是,它有望引发内部子请求在将请求传递给 PHP 处理程序之前,对错误文档进行检查(这似乎与错误文档相冲突)。然后,PHP 处理程序只会被调用来提供错误文档。