URL 掩码对省略尾部斜杠的 URL 不起作用
URL masking not working for URLs that omit the trailing slash
有很多类似的问题,但none似乎很适合我。
我正在从 WordPress 网站转移到简单的静态网站。
但是,我目前被禁止完全删除托管在 public_html
文件夹中的 WordPress 网站,直到一切都被证明可以与静态网站一起使用。
我已将静态站点部署到我的 public_html
文件夹中的子文件夹中,例如/subfolderA/newSiteFolder
.
我已经更新 .htaccess
以使用以下内容重定向到子文件夹:
RewriteEngine on
RewriteCond %{REQUEST_URI} !newSiteFolder/
RewriteCond %{REQUEST_URI} !subfolderA/newSiteFolder/
RewriteRule (.*)$ /subfolderA/newSiteFolder/ [L]
当从站点内部按 links 导航站点时,这工作正常并在地址栏中正确显示,但是当从外部 link 导航到站点时,子文件夹是显示在地址栏中。
例如,如果从外部点击关于页面 link,它显示为
https://example.com/subfolderA/newSiteFolder/about
,而不是 https://example.com/about
。
从外部 link 单击时,如何屏蔽地址栏中的子文件夹名称?或者如何最好地更改我的重写规则来完成此操作?
我假设 about
实际上是 /subfolderA/newSiteFolder/about
中的物理子目录,并且您打算从中提供 DirectoryIndex
文档(例如 index.html
)目录。
“问题”是,当您请求目录时 没有 尾部斜杠 mod_dir 试图通过 301 ( permanent) 重定向,这暴露了内部重写的 file-path.
换句话说,当您请求 /about
(没有尾部斜线)时,您的 mod_rewrite 指令在内部将请求重写为 /subfolderA/newSiteFolder/about
,但随后 mod_dir 开始并在外部将请求重定向到 /subfolderA/newSiteFolder/about/
以附加尾部斜杠(这是必需的)。
规范 URL 包含尾部斜杠,这就是您在内部链接的内容。所以我们需要确保在映射到目录时重写的 URL 上始终有一个尾部斜杠。我们可以在重写 URL.
之前 canonical 重定向
RewriteCond %{REQUEST_URI} !newSiteFolder/
RewriteCond %{REQUEST_URI} !subfolderA/newSiteFolder/
RewriteRule (.*)$ /subfolderA/newSiteFolder/ [L]
第一个条件似乎是多余的。而且,这里使用的正则表达式不是 anchored,所以在请求的 URL-path.
中的任何地方匹配规定的 URL
但是,我们不能只将尾部斜杠附加到所有 URL,因为您可能有静态资源,如 CSS、JS 和图像等。对于任何静态文件,我们不能强制使用尾部斜杠,因此我们需要使用附加规则来处理这个问题。请尝试以下操作:
# Store the base directory in an environment variable
RewriteRule ^ - [E=BASEDIR:/subfolderA/newSiteFolder/]
# Rewrite the root (homepage) only
RewriteRule ^$ %{ENV:BASEDIR} [L]
# Finish early if we are already in the required base directory
RewriteCond %{ENV:BASEDIR}@%{REQUEST_URI} ^([^@]+)@
RewriteRule ^ - [L]
# If the request would map to a directory
# and it is missing a trailing slash
# then redirect to append the trailing slash
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}%{ENV:BASEDIR} -d
RewriteRule ^(.+[^/])$ // [R=301,L]
# Rewrite everything to the base directory
RewriteRule (.+) %{ENV:BASEDIR} [L]
以上指令的解释
我选择使用第一条规则将“基本目录”(即 /subfolderA/newSiteFolder/
)存储在环境变量 BASEDIR
中,以保存基本目录 file-path 在整个过程中的重复文件。
RewriteCond %{ENV:BASEDIR}@%{REQUEST_URI} ^([^@]+)@
这个条件检查请求的URL(包括重写的URL)是否已经在被重写的基本目录中。 @
字符只是一个没有出现在 URL-path 中的任意字符,它在正则表达式中没有特殊含义,除了将基本目录 (BASEDIR
) 与请求的 URL (REQUEST_URI
)。 </code> 是内部反向引用,用于检查所请求的 URL 是否以基目录开头。</p>
<blockquote>
<pre><code>RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}%{ENV:BASEDIR} -d
RewriteRule ^(.+[^/])$ // [R=301,L]
第一个 条件 排除任何以 looks-like 文件扩展名结尾的请求(即一个点后跟 2 到 4 个字符),因此我们可以避免更昂贵的目录检查(如下)。这确实假设您没有以 looks-like “文件扩展名”结尾的物理目录。
第二个条件测试请求的URL(例如/about
)是否作为目录存在于被重写到的目录中。
正则表达式 ^(.+[^/])$
匹配(并捕获)任何未以斜杠结尾的 URL-path。
注意:您需要确保在测试之前已清除浏览器缓存,因为之前的 错误 重定向附加了尾部斜线(这也暴露了 file-path ) 是一个 301 永久 重定向,很可能已被浏览器永久缓存。
防止直接访问“隐藏”子目录
Is there a way to also fix the URL for a user who was previously navigated to mydomain/subfolderA/newSiteFolder/about
from the external link and saved the link with the subfolders, and is now using that link directly?
您可以阻止直接访问此“隐藏”子目录并将用户重定向回“规范”URL,方法如下。这应该作为上面块中的第三条规则,在“重写根...”规则之后。
# Redirect direct requests to the subdirectory back to root
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{ENV:BASEDIR}@%{REQUEST_URI} ^([^@]+)@(.*)
RewriteRule ^ /%2 [R=301,L]
重要的是,检查 REDIRECT_STATUS
env var 的第一个条件排除了后来重写的重写请求,因此此规则仅影响来自客户端的直接请求。
%2
是对前面 CondPattern 中第二个捕获组的反向引用,即。 URL-path BASEDIR
.
之后的所有内容
但是,如果用户之前被错误地重定向到子目录,那么这个 redirect 可能会被浏览器缓存,所以上面的重定向删除(撤消)不幸的是,子目录可能会导致这些用户的 redirect-loop,直到他们清除浏览器缓存。 (此 redirect-loop 可能会 提示他们尝试清除浏览器缓存以解决问题;尽管可能不会。)
您或许可以重定向回包含无害查询字符串的 URL。这可能足以防止那些缓存了错误重定向的用户的重定向循环(因为它不是 URL 在他们的缓存中),但它确实会在 URL 上留下多余的查询字符串。比如把上面的RewriteRule
指令改成:
:
RewriteRule ^ /%2?noredirect [R=301,L]
noredirect
只是任何查询字符串,以区别于缓存的 URL/redirect.
注意:首先使用 302(临时)重定向进行测试以避免 further/potential 缓存问题。
总结
RewriteEngine On
# Store the base directory in an environment variable
RewriteRule ^ - [E=BASEDIR:/subfolderA/newSiteFolder/]
# Rewrite the root (homepage) only
RewriteRule ^$ %{ENV:BASEDIR} [L]
# Redirect direct requests to the subdirectory back to root
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{ENV:BASEDIR}@%{REQUEST_URI} ^([^@]+)@(.*)
RewriteRule ^ /%2 [R=301,L]
# Finish early if we are already in the required base directory
RewriteCond %{ENV:BASEDIR}@%{REQUEST_URI} ^([^@]+)@
RewriteRule ^ - [L]
# If the request would map to a directory
# and it is missing a trailing slash
# then redirect to append the trailing slash
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}%{ENV:BASEDIR} -d
RewriteRule ^(.+[^/])$ // [R=301,L]
# Rewrite everything to the base directory
RewriteRule (.+) %{ENV:BASEDIR} [L]
有很多类似的问题,但none似乎很适合我。
我正在从 WordPress 网站转移到简单的静态网站。
但是,我目前被禁止完全删除托管在 public_html
文件夹中的 WordPress 网站,直到一切都被证明可以与静态网站一起使用。
我已将静态站点部署到我的 public_html
文件夹中的子文件夹中,例如/subfolderA/newSiteFolder
.
我已经更新 .htaccess
以使用以下内容重定向到子文件夹:
RewriteEngine on
RewriteCond %{REQUEST_URI} !newSiteFolder/
RewriteCond %{REQUEST_URI} !subfolderA/newSiteFolder/
RewriteRule (.*)$ /subfolderA/newSiteFolder/ [L]
当从站点内部按 links 导航站点时,这工作正常并在地址栏中正确显示,但是当从外部 link 导航到站点时,子文件夹是显示在地址栏中。
例如,如果从外部点击关于页面 link,它显示为
https://example.com/subfolderA/newSiteFolder/about
,而不是 https://example.com/about
。
从外部 link 单击时,如何屏蔽地址栏中的子文件夹名称?或者如何最好地更改我的重写规则来完成此操作?
我假设 about
实际上是 /subfolderA/newSiteFolder/about
中的物理子目录,并且您打算从中提供 DirectoryIndex
文档(例如 index.html
)目录。
“问题”是,当您请求目录时 没有 尾部斜杠 mod_dir 试图通过 301 ( permanent) 重定向,这暴露了内部重写的 file-path.
换句话说,当您请求 /about
(没有尾部斜线)时,您的 mod_rewrite 指令在内部将请求重写为 /subfolderA/newSiteFolder/about
,但随后 mod_dir 开始并在外部将请求重定向到 /subfolderA/newSiteFolder/about/
以附加尾部斜杠(这是必需的)。
规范 URL 包含尾部斜杠,这就是您在内部链接的内容。所以我们需要确保在映射到目录时重写的 URL 上始终有一个尾部斜杠。我们可以在重写 URL.
之前 canonical 重定向RewriteCond %{REQUEST_URI} !newSiteFolder/ RewriteCond %{REQUEST_URI} !subfolderA/newSiteFolder/ RewriteRule (.*)$ /subfolderA/newSiteFolder/ [L]
第一个条件似乎是多余的。而且,这里使用的正则表达式不是 anchored,所以在请求的 URL-path.
中的任何地方匹配规定的 URL但是,我们不能只将尾部斜杠附加到所有 URL,因为您可能有静态资源,如 CSS、JS 和图像等。对于任何静态文件,我们不能强制使用尾部斜杠,因此我们需要使用附加规则来处理这个问题。请尝试以下操作:
# Store the base directory in an environment variable
RewriteRule ^ - [E=BASEDIR:/subfolderA/newSiteFolder/]
# Rewrite the root (homepage) only
RewriteRule ^$ %{ENV:BASEDIR} [L]
# Finish early if we are already in the required base directory
RewriteCond %{ENV:BASEDIR}@%{REQUEST_URI} ^([^@]+)@
RewriteRule ^ - [L]
# If the request would map to a directory
# and it is missing a trailing slash
# then redirect to append the trailing slash
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}%{ENV:BASEDIR} -d
RewriteRule ^(.+[^/])$ // [R=301,L]
# Rewrite everything to the base directory
RewriteRule (.+) %{ENV:BASEDIR} [L]
以上指令的解释
我选择使用第一条规则将“基本目录”(即 /subfolderA/newSiteFolder/
)存储在环境变量 BASEDIR
中,以保存基本目录 file-path 在整个过程中的重复文件。
RewriteCond %{ENV:BASEDIR}@%{REQUEST_URI} ^([^@]+)@
这个条件检查请求的URL(包括重写的URL)是否已经在被重写的基本目录中。 @
字符只是一个没有出现在 URL-path 中的任意字符,它在正则表达式中没有特殊含义,除了将基本目录 (BASEDIR
) 与请求的 URL (REQUEST_URI
)。 </code> 是内部反向引用,用于检查所请求的 URL 是否以基目录开头。</p>
<blockquote>
<pre><code>RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}%{ENV:BASEDIR} -d
RewriteRule ^(.+[^/])$ // [R=301,L]
第一个 条件 排除任何以 looks-like 文件扩展名结尾的请求(即一个点后跟 2 到 4 个字符),因此我们可以避免更昂贵的目录检查(如下)。这确实假设您没有以 looks-like “文件扩展名”结尾的物理目录。
第二个条件测试请求的URL(例如/about
)是否作为目录存在于被重写到的目录中。
正则表达式 ^(.+[^/])$
匹配(并捕获)任何未以斜杠结尾的 URL-path。
注意:您需要确保在测试之前已清除浏览器缓存,因为之前的 错误 重定向附加了尾部斜线(这也暴露了 file-path ) 是一个 301 永久 重定向,很可能已被浏览器永久缓存。
防止直接访问“隐藏”子目录
Is there a way to also fix the URL for a user who was previously navigated to
mydomain/subfolderA/newSiteFolder/about
from the external link and saved the link with the subfolders, and is now using that link directly?
您可以阻止直接访问此“隐藏”子目录并将用户重定向回“规范”URL,方法如下。这应该作为上面块中的第三条规则,在“重写根...”规则之后。
# Redirect direct requests to the subdirectory back to root
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{ENV:BASEDIR}@%{REQUEST_URI} ^([^@]+)@(.*)
RewriteRule ^ /%2 [R=301,L]
重要的是,检查 REDIRECT_STATUS
env var 的第一个条件排除了后来重写的重写请求,因此此规则仅影响来自客户端的直接请求。
%2
是对前面 CondPattern 中第二个捕获组的反向引用,即。 URL-path BASEDIR
.
但是,如果用户之前被错误地重定向到子目录,那么这个 redirect 可能会被浏览器缓存,所以上面的重定向删除(撤消)不幸的是,子目录可能会导致这些用户的 redirect-loop,直到他们清除浏览器缓存。 (此 redirect-loop 可能会 提示他们尝试清除浏览器缓存以解决问题;尽管可能不会。)
您或许可以重定向回包含无害查询字符串的 URL。这可能足以防止那些缓存了错误重定向的用户的重定向循环(因为它不是 URL 在他们的缓存中),但它确实会在 URL 上留下多余的查询字符串。比如把上面的RewriteRule
指令改成:
:
RewriteRule ^ /%2?noredirect [R=301,L]
noredirect
只是任何查询字符串,以区别于缓存的 URL/redirect.
注意:首先使用 302(临时)重定向进行测试以避免 further/potential 缓存问题。
总结
RewriteEngine On
# Store the base directory in an environment variable
RewriteRule ^ - [E=BASEDIR:/subfolderA/newSiteFolder/]
# Rewrite the root (homepage) only
RewriteRule ^$ %{ENV:BASEDIR} [L]
# Redirect direct requests to the subdirectory back to root
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{ENV:BASEDIR}@%{REQUEST_URI} ^([^@]+)@(.*)
RewriteRule ^ /%2 [R=301,L]
# Finish early if we are already in the required base directory
RewriteCond %{ENV:BASEDIR}@%{REQUEST_URI} ^([^@]+)@
RewriteRule ^ - [L]
# If the request would map to a directory
# and it is missing a trailing slash
# then redirect to append the trailing slash
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}%{ENV:BASEDIR} -d
RewriteRule ^(.+[^/])$ // [R=301,L]
# Rewrite everything to the base directory
RewriteRule (.+) %{ENV:BASEDIR} [L]