Apache htaccess 规则集:尝试以如下方式请求:1) 文件原样 2) 文件 + .html 后缀 3) DirectoryIndex 4) 否则转至 index.php CMS 路由器

Apache htaccess 规则集:尝试以如下方式请求:1) 文件原样 2) 文件 + .html 后缀 3) DirectoryIndex 4) 否则转至 index.php CMS 路由器

我想表达这个规则集

如果请求是,/hello则按给定的顺序尝试以下操作:

  1. /hello— 该名称的文件存在(没有文件扩展名的文件)。
    • 编辑:不是必需的。只是一种可能性/妥协。如果太复杂则放弃。
  2. /hello.html- 存在该名称加上 .html 扩展名的文件。
  3. /hello/index.(htm|html|php)— 存在具有索引文件的同名文件夹。注意:明确禁止列出 /hello/ 目录
  4. /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

问题

  1. mod_dirDirectoryIndex独作:
  • ✅ 请求的/a01服务/a01是没有后缀的文件。
  • ✅ 请求/a02服务/a02/index.html即 DirectoryIndex。
  1. 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 路由呢。
  1. 因此mod_dirmod_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。

相关内容