apache - 当模式为 ^(.*)$ 时,为什么 $1 不存储完整的 URL?
问题描述
已经有几个关于这个的话题。但是我还没有找到答案,或者我仍然没有正确理解它。
我知道这$1
代表了 RewriteRule 正则表达式中第一组括号的匹配。$1
也存储这个值。
但如果只有^(.*)$
,那么它的工作方式似乎有所不同?
示例:
网址:http://www.example.com/
RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC,OR]
RewriteCond %{HTTPS_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
我的理解:
1.http://www.example.com/
匹配RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
并将匹配存储在%1
(=example.com/)中。
2. 转到 RewriteRule,因为在步骤 1 中匹配的 URL
3. RewriteRule 获取字符串http://www.example.com/
。因为^(.*)$
,http://www.example.com/
完全匹配并存储在$1
.
4. 我认为这个 URL 应该出现:https://example.com/http://www.example.com/
实际出现的内容:https://example.com/
为什么$1
会有一个空字符串?这一切都匹配,不是吗?
解决方案
这里有很多误解,我将尝试解决...
RewriteBase / RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC,OR] RewriteCond %{HTTPS_HOST} ^www\.(.*)$ [NC] RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
我将忽略RewriteBase
指令和第二个RewriteCond
指令......
该RewriteBase
指令不适用于此处,因为没有相对路径替换字符串(该RewriteRule
指令的第二个参数)。
没有HTTPS_HOST
服务器变量,只有HTTP_HOST
. 请参阅有关 ServerFault 的以下问题:https ://serverfault.com/questions/953020/what-is-the-difference-between-http-host-and-https-host-in-apache-htaccess-file
我认为HTTPS_HOST
由于一些被盲目复制/粘贴的拼写错误/误解而在互联网上长期存在。
HTTP_HOST
包含Host
HTTP 请求标头(主机名)的值,例如。www.example.com
或者example.com
,取决于请求的内容。因此名称HTTP_
+ HOST
。这是用于所有 HTTP 请求标头的相同命名约定。为每个创建相应的服务器变量。
因此,这变为(OR
从第一个条件中删除标志):
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
RewriteRule
模式(例如^(.*)$
)
但如果只有
^(.*)$
,那么它的工作方式似乎有所不同?
不,它的工作原理相同。混乱似乎是该RewriteRule
模式实际匹配的内容。
该RewriteRule
模式仅与 URL 路径匹配。
URL 路径是在方案 + 主机名之后和查询字符串之前的 URL 部分。例如。给定一个请求,http://example.com/
那么 URL-path 就是简单的/
. 或请求http://example.com/foo/bar?param=1
- URL 路径是/foo/bar
.
但是,在每个目录的上下文中.htaccess
(与服务器或虚拟主机上下文相反),在匹配发生之前首先从 URL 路径中删除目录前缀。(因为在请求映射到文件系统并且严格来说与文件路径匹配之后进行处理。)目录前缀是文件本身的绝对文件路径,特别是以斜杠结尾。例如。当文件位于文档根目录中时,目录前缀将类似于(文档根目录的文件系统路径)。.htaccess
.htaccess
.htaccess
/var/www/user/public_html/
所以,给定一个请求,那么与模式匹配的http://example.com/
URL 路径就是“”(空字符串)。或者请求- 匹配的 URL 路径是- 没有斜杠前缀。RewriteRule
.htaccess
http://example.com/foo/bar?param=1
foo/bar
.htaccess
当文件位于文档根目录之外的子目录中时,这一点更为重要。例如,如果.htaccess
文件位于/subdir
子目录中并且有表单的请求,则http://example.com/subdir/foo/bar
该RewriteRule
模式将再次与 just foo/bar
(not subdir/foo/bar
or /subdir/foo/bar
) 匹配。这与在服务器(或虚拟主机)上下文RewriteRule
中使用指令时存在显着差异。在服务器上下文中,该模式始终与完整的 URL 路径匹配,以斜杠开头 - 在服务器上下文中使用时没有目录前缀的概念,因为指令是在之前处理的RewriteRule
请求被映射到文件系统。
我的理解:
http://www.example.com/
匹配RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
并将匹配存储在%1
(=example.com/) 中。- 转到
RewriteRule
因为在步骤 1 中匹配的 URL- RewriteRule 获取字符串
http://www.example.com/
。因为^(.*)$
,http://www.example.com/
完全匹配并存储在$1
.- 我认为这个 URL 应该出现:
https://example.com/http://www.example.com/
您的处理顺序错误。它实际上是首先处理的RewriteRule
模式。仅当RewriteRule
模式匹配时才处理前面的RewriteCond
(条件)。如果所有条件都成功,则发生RewriteRule
替换(第二个参数)。
因此,按顺序,给定一个请求http://www.example.com/
:
RewriteRule ^(.*)$
- 生成的 URL 路径“”(空字符串)与RewriteRule
模式^(.*)$
匹配。然后$1
反向引用保存一个空字符串($0
反向引用也是如此 - 它存储整个模式的匹配 - 在这种情况下相同)RewriteCond %{HTTP_HOST} ^www\.(.*)$
- 如果RewriteRule
模式在步骤#1 中匹配(在这种情况下匹配),则RewriteCond
处理前面的指令。这与Host
标题匹配,例如。www.example.com
(否http://
)反对正则表达式^www\.(.*)$
。如果这成功,则%1
反向引用保存第一个捕获组的值,即。example.com
在这个例子中。RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
- 如果前面的条件成功,则指令中的替换(即https://%1/$1
)发生。RewriteRule
IE。https://example.com/
-来自最后一个匹配的CondPattern%1
中的捕获组,并且是一个空字符串,来自模式中的捕获组。example.om
$1
RewriteRule
其他注意事项:
- 由于处理的顺序,在
RewriteRule
模式中尽可能多地进行模式匹配,而不是依赖于前面的RewriteCond
指令,自然会更有效率。(一个常见的误解是RewriteCond
指令首先被处理——事实并非如此。)
由于处理顺序,您可以在前面指令的TestString
$n
(第一个)参数中使用反向引用。(如果指令是自上而下处理的,这是不可能的。)RewriteCond
%n
反向引用仅来自最后匹配 的CondPattern。如果您有多种情况,请务必考虑这一点。
推荐阅读
- css - VSCode中不能更改.css.map文件的路径吗?
- python - 验证码不起作用,为什么会这样?
- php - 文件上传不会在 AWS S3 中被覆盖
- linux - 使用公式合并两个文件
- javascript - 用于隔离单词/拆分单词的 JavaScript 正则表达式
- java - 使用 dialogflow v2 api 获取事件列表
- javascript - 在javascript中访问php数组中的值
- dataframe - 如何获取 .dat 文件的数据框?
- java - Java 连接到 SQL Server 数据库 - 用户错误消息登录失败
- elasticsearch - 我可以请求弹性字段以匹配特定顺序的数据吗?