如果 index.html 不存在于没有尾部斜杠的目录中,则服务 index.php

Serve index.php if index.html is not present in directory without a trailing slash

我有一个带有子目录的 HTML 网站。

我需要的是:

  1. 访问没有尾部斜杠的子目录,即。 (example.com/blog) 不是 (example.com/blog/)
  2. 如果某个子目录下没有index.html,它应该寻找index.php

/blog/ 页面是一个带有自己 .htaccess.

的 WordPress 页面

这是我当前的根 .htaccess:

RewriteEngine on
ErrorDocument 404 /error/error404.html


DirectorySlash Off
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/index.html -f
RewriteRule ^(.*)$ //index.html [L]

WordPress .htaccess/blog/.htaccess:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /blog/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /blog/index.php [L]
</IfModule>

(由 Wordpress 自动生成)

至于现在,html 文件可以在某些子目录下访问,但不能使用 index.php。我该怎么办?

DirectoryIndex 文档列出了在请求目录时尝试提供的文件。你不需要mod_rewrite。

但是,要在设置 DirectorySlash Off 时使用 DirectoryIndex,您需要手动将尾部附加到具有内部重写的目录,否则,即使该目录包含,也会触发 403一份 DirectoryIndex 文件。 (正是出于这个原因,需要禁用 mod_autoindex 以防止意外泄露信息 - DirectoryIndex 文档的存在不足以防止 DirectorySlash Off 时自动生成的目录列表已设置。)

例如:

# Disable directory listings (mod_autoindex)
Options -Indexes

ErrorDocument 404 /error/error404.html

# Look for index.html then index.php in the directory being requested
DirectoryIndex index.html index.php

# Prevent mod_dir appending the trailing slash
DirectorySlash Off

RewriteEngine On

# If request a directory without a trailing slash then rewrite to append it
# This allows DirectoryIndex to work as intended
# - exclude the document root
RewriteCond  !/$
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule (.+) / [L]

确保清除浏览器缓存。 mod_dir 发出 301(永久)重定向以附加尾部斜线。


更新#1:

/blog/ page is a WordPress page with its own .htaccess.

问题在于,当在子目录中启用重写引擎时,它会完全覆盖父配置中的 mod_rewrite 指令,因此不会附加斜线,也不会触发目录索引( mod_rewrite 指令由于缺少斜线而未被处理)。 (这感觉有点先有鸡还是先有蛋。)

我成功解决这个问题的唯一方法是将 WordPress 指令移动到父配置中(进行必要的更改)并完全删除 /blog/.htaccess

例如,在上述指令之后附加以下修改后的 WordPress 指令:

# WordPress in "/blog" subdirectory
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteRule ^blog/index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^blog/. /blog/index.php [L]

更新#2:

have URL with trailing slash to redirect to URL without trailing slash? like for example, if I visit /about/ it should redirect to /about?

是的,我们可以做到。由于我们要从 everything 中删除尾部斜杠,包括目录,这基本上是无条件的。唯一需要注意的是,删除尾部斜杠的规则必须仅适用于来自客户端的直接请求,而不适用于后来重写的重写请求,后者将尾部斜杠附加到目录,否则会导致重定向循环。

旁白: 你显然需要确保你所有的内部链接都不包含尾部斜杠,否则,用户将体验到外部重定向(对 SEO 和你的服务器不利).

我们可以通过检查 REDIRECT_STATUS 环境变量来做到这一点,该变量在初始请求中为 empty,并设置为 200(如200 OK 状态)在第一次成功重写后(将尾部斜杠附加到目录)。

例如,以下内容应紧跟在 RewriteEngine 指令之后,现有重写之前:

# Redirect direct requests to remove trailing slash from all URLs
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.+)/$ / [R=302,L]

首先使用 302(临时)重定向进行测试,并在确认其按预期工作后更改为 301(永久)重定向。这是为了避免潜在的缓存问题。

总结

所有指令都已到位:

# Disable directory listings (mod_autoindex)
Options -Indexes

ErrorDocument 404 /error/error404.html

# Look for index.html then index.php in the directory being requested
DirectoryIndex index.html index.php

# Prevent mod_dir appending the trailing slash
DirectorySlash Off

RewriteEngine On

# Redirect direct requests to remove trailing slash from all URLs
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.+)/$ / [R=301,L]

# If request a directory without a trailing slash then rewrite to append it
# - This allows DirectoryIndex to work as intended
# - Exclude the document root
RewriteCond  !/$
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule (.+) / [L]

# WordPress in "/blog" subdirectory
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteRule ^blog/index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^blog/. /blog/index.php [L]