我想表达这个规则集
如果请求是,/hello
则按给定的顺序尝试以下操作:
/hello
— 该名称的文件存在(没有文件扩展名的文件)。- 编辑:不是必需的。只是一种可能性/妥协。如果太复杂则放弃。
/hello.html
- 存在该名称加上 .html 扩展名的文件。/hello/index.(htm|html|php)
— 存在具有索引文件的同名文件夹。注意:明确禁止列出 /hello/ 目录/index.php
— 如果以上都不匹配,则交给 CMS index.php(例如 Wordpress)
我的共享主机账户的域根文件夹中的 .htaccess 文件:
## Request without file extension
# e.g. "/hello"
### First look for DirectoryIndex files (with mod_dir)
# e.g. "/hello" shall serve "/hello/index.(html|htm|php)" if present
# Explicitly forbidding directory listings (for security/privacy)
<IfModule mod_dir.c>
Options -Indexes
DirectoryIndex index.html index.htm index.php
</IfModule>
### If no DirectoryIndex found then try with .html suffix (with mod_rewrite)
# e.g. "/hello" shall serve "/hello.html" if present
<IfModule mod_rewrite.c>
RewriteRule ^([^\.]+)$ $1.html [NC,L]
</IfModule>
## Everything else goes to Wordpress index.php and its standard htaccess configuration like this:
# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
问题
mod_dir
的DirectoryIndex
独作:
- ✅ 请求的
/a01
服务/a01
是没有后缀的文件。 - ✅ 请求
/a02
服务/a02/index.html
即 DirectoryIndex。
mod_rewrite
'sRewriteRule
尝试添加.html suffix
单独的作品:
- ✅ 请求
/a03
服务/a03.html
。 - ❌ 但现在要求
/a02
退货Apache error page 403 Access forbidden
。 - ❌ 现在请求
/a01
退货Wordpress error page 404 Not found
。- 奇怪的是,因为该文件存在,因此在 htaccess Wordpress 部分
RewriteCond %{REQUEST_FILENAME} !-f
甚至没有得到满足,那么它怎么能进入 Wordpress 路由呢。
- 奇怪的是,因为该文件存在,因此在 htaccess Wordpress 部分
- 因此
mod_dir
,mod_rewrite
规则同时生效似乎会导致冲突。
- 我的网站托管中心规则是否会干扰这一点?
- 或者这是两个模块之间一般的相互作用问题?如何让它们按预期协同工作?
答案1
如果没有匹配的 #3 DirectoryIndex 则继续 #4 CMS
您不能“优雅地”使用 mod_dir 失败DirectoryIndex
,然后使用 mod_rewrite 对请求执行其他操作(即,将请求路由到 CMS 的 #4)。mod_dir 处理得太晚了。因此,DirectoryIndex
我们需要使用模拟使用 mod_rewrite 来实现。
但是,这里的另一个(小)问题是需要编辑 WordPress 代码块(正如评论所述,不应手动编辑)以允许将文件系统目录的请求传递给 CMS。
我假设对目录的任何直接请求都应包含尾部斜杠。例如,如果/hello
是物理目录,则应请求/hello/
(带有尾部斜杠)。如果省略,我们将附加尾部斜杠(mod_dir 默认会这样做,但如果覆盖,我们需要手动执行此操作Directoryindex
)。我们可以禁用尾部斜杠(并使规范 URL 成为没有尾部斜杠的 URL),但这需要额外的重写。
因此,为了满足您的要求,您可以在根文件中这样做.htaccess
:
Options -Indexes
# Required for the root directory (eg. the homepage of the CMS)
DirectoryIndex index.html index.htm index.php
RewriteEngine On
# Initially part of the WordPress/CMS block
# (This is just an optimisation)
RewriteRule ^index\.php$ - [L]
# Abort early if a file is requested directly
# (Regardless of whether that file includes a file extension.)
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule . - [L]
# If a directory is requested, which is missing the trailing slash then append it
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule ^(.*[^/])$ /$1/ [R=301,L]
# Test if "<url>.html" exists and rewrite if so
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
RewriteRule ^([^.]*[^/])$ $1.html [L]
# Optimisation: If a directory is not requested then skip the next 3 rules
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . - [S=3]
# Check for "DirectoryIndex" documents in order: index.html, index.htm and index.php
# NB: Directories end in a trailing slash (enforced above)
RewriteCond %{DOCUMENT_ROOT}/$1/index.html -f
RewriteRule ^(.+)/$ $1/index.html [L]
RewriteCond %{DOCUMENT_ROOT}/$1/index.htm -f
RewriteRule ^(.+)/$ $1/index.htm [L]
RewriteCond %{DOCUMENT_ROOT}/$1/index.php -f
RewriteRule ^(.+)/$ $1/index.php [L]
# CMS Fallback...
# But note that the two conditions (filesystem checks) are removed.
# The first one that checks for a "file" is simply not required.
# However, the second check MUST be removed otherwise directories that do not contain a "DirectoryIndex" are not routed to the CMS.
# WordPress...
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# CMS / Front-Controller
RewriteRule . /index.php [L]
补充笔记:
作为一项优化,我假设您映射到
.html
文件的 URL 不包含点。这就是您所做的,所以我认为这没问题。(在正则表达式字符类中使用时,无需对文字点进行反斜杠转义。)我删除了 WordPress 注释标记,并将 WordPress 代码块缩减为所需的全部内容。其中一个
RewriteRule
指令被移至文件顶部.htaccess
(因为这是优化,所以将其放在文件末尾没有多大意义)。您需要配置 WordPress(或您的文件权限)以防止 WordPress 尝试维护该.htaccess
文件(尽管这可能会导致插件出现问题)。将文件系统目录传递给 CMS 显然是非标准的。大多数 CMS 的样板代码(前端控制器模式)将明确排除物理目录。然而,这里增加的复杂性是,您只希望将 DirectoryIndex 文档不存在于该目录中的目录传递给 CMS。
我喜欢保留没有后缀的文件的可能性。
底层文件没有文件扩展名的“问题”是 Apache 不一定知道如何处理请求以及要发送什么“Content-Type”标头(因此浏览器不知道如何处理响应)。
在这种情况下,一种解决方法是将所有无扩展名的特定类型的“文件”放在已知子目录中,然后力量所有具有相同 Content-Type 的请求。
请注意,文件和 URL 在这方面有很大不同。没有扩展名的 URL 没有问题。
在旁边:
RewriteRule ^([^\.]+)$ $1.html [NC,L]
此规则的问题在于,您无条件地将.html
扩展名应用于任何不包含点的 URL。/a01
被重写为/a01.html
,它不是文件(因此状况成功)并且/a01
(WP 看到的 URL)不是注册的 WP URL,因此导致 CMS/WordPress 生成 404。