【问题标题】:What is the meaning of ^ and $ in Apache HTTPD RewriteRule?Apache HTTPD RewriteRule 中的 ^ 和 $ 是什么意思?
【发布时间】:2020-04-12 11:14:33
【问题描述】:

我已成功将以下代码添加到我的 Apache HTTPD 配置中:

# Force www.
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
# Force https (SSL)
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

虽然它按预期工作,但我有一个理论上的问题:

为什么在第 3 行有一个 ^$ 强制执行“www.”,而不是在第 6 行强制执行“https”?

此致,多维德。

【问题讨论】:

    标签: apache .htaccess mod-rewrite httpd.conf


    【解决方案1】:

    对于您的两个正则表达式模式^(.*)$(.*) 将表现相同。但是你猜怎么着,你不需要使用它们中的任何一个。事实上,不使用.* 并使用匹配完整URI 的%{REQUEST_URI} 变量(不是像.* 这样的相对变量)也不容易出错。所以我建议把你的规则改成这样:

    # Force www.
    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
    
    # Force https (SSL)
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
    
    • 标志NE 用于不转义。如果您的原始 URI 包含一些特殊字符,例如 #(,),[,] 等,则使用此标志很有用。
    • 上面RewriteRule 模式中的^ 什么都不做,只会为每个匹配项返回true,因为^ 表示字符串的开始位置,它将始终匹配。
    • 这两个规则可以组合成一个规则,但看起来有点复杂。

    这里是:

    RewriteCond %{HTTP_HOST} !^www\. [NC,OR]
    RewriteCond %{HTTPS} !on
    RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
    RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L,NE]
    

    下面是这条规则的解释:

    • RewriteCond %{HTTP_HOST} !^www\. [NC,OR]: 如果HOST_NAME 不以www. 开头
    • [NC,OR]:忽略大小写匹配和ORs 下一个条件
    • RewriteCond %{HTTPS} !onHTTPS 未开启
    • RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]:此条件将始终匹配,因为 www. 在此处是可选匹配。它用于捕获HTTP_HOST 的子字符串,而无需在捕获组#1 中使用(.+) 模式启动www.(稍后将反向引用为%1)。请注意,(?:..) 是非捕获组。
    • RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L,NE]^ 将始终匹配。通过将https://www. 添加到%1,此规则将重定向到带有R=301 代码的https://www.%1%{REQUEST_URI}%1 是来自RewriteCond 的捕获组#1 的反向引用,如上所述。

    【讨论】:

      【解决方案2】:

      如果使用 Apache 的模块 mod_rewrite,那么您可以定义一个 RewriteRule

      RewriteRule 使用正则表达式

      关键字或指令 RewriteRule 后跟 Regular Expression(也称为 RegExpattern)。此 RegEx(例如 ^(.*)$)用于匹配输入 URL 以便重写它们。

      正则表达式使用特殊字符编码

      RegEx 模式中,^ 标记要匹配的行的开头,而结尾由 $ 表示。

      两者都称为元字符并具有特殊含义:

      ^:匹配字符串中的起始位置。在基于行的工具中,它匹配任何行的起始位置。

      $:匹配字符串的结束位置或字符串结束换行符之前的位置。在基于行的工具中,它匹配任何行的结束位置。

      为什么它们经常过时?

      由于到达 HTTP 服务器的 URL 总是由一行表示,这些 行分隔 元字符也可以省略而不影响模式/重写规则。

      【讨论】:

      • B"H 你好 hc_dev 我现在明白为什么在这种情况下没有区别,谢谢你。真诚的,Dovid。
      【解决方案3】:

      它们是一样的。 ^(.*)$(.*) 没有区别。

      .* 匹配任何字符串。 ^$ 不要更改它,因为所有字符串都有开始和结束。

      【讨论】:

      • B"H 感谢匿名者的回复。在任何文档中都提到过吗?此致,Dovid。
      • @Dovid 这些是正则表达式控制字符。 ^ 表示“字符串的开头”。 $ 表示“字符串结束”。在这种特定的情况下,它们具有相同的含义。在其他情况下,它们可能很重要。
      • @Dovid 否,但httpd.apache.org/docs/current/rewrite/intro.html 上有一些示例显示.* 匹配所有内容。 ^$ 不要改变它。
      • B"H 再次感谢匿名用户的额外回复。此致,Dovid。
      • 不要做那种不加解释就...简洁地回答的人;-)
      【解决方案4】:

      这取决于您是否为不带 www 或带 www 的域制作了证书。

      在提供的示例中,重定向(第 6 行)是对域 没有 www。这样可以保证提供正确的证书,并且浏览器在访问您的网站时不会显示警报。

      【讨论】:

      • B"H 感谢 Skatox 的回复。如果没有“www.”,则代码的前半部分(第 3 行)会同时添加“www.”和“https”。如果“www.”已经存在,那么第 6 行中“{HTTP_HOST}”的那部分不是吗?因为如果不是,那么地址将保留没有“www.”,而实际上是“www.”。总是添加。我必须承认,我不知道如何检查两者中的哪一个,www。或非 www.,有我的 Hostgator 提供商颁发给它的证书。甚至不知道这有什么不同。此致,多维德。
      • HTTP_HOST 只是域,没有别的。如果我的回答帮助您记得将其标记为已解决并投票:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多