Apache mod_alias RedirectMatch 除特定模式外的所有内容
Posted
技术标签:
【中文标题】Apache mod_alias RedirectMatch 除特定模式外的所有内容【英文标题】:Apache mod_alias RedirectMatch everything except specific pattern 【发布时间】:2014-12-11 13:12:00 【问题描述】:好旧的正则表达式快把我逼疯了。
我需要使用 Redirect from mod_alias(不能使用 mod_rewrite)将 Apache 2.4 中的所有流量从 HTTP 重定向到 HTTPS,“/bt/sub/[a_few_endings]”除外。
我在我认识的所有在线测试人员(例如http://regex101.com/)中测试了以下正则表达式,并且所有人都确认该正则表达式确实应该匹配除我不希望它匹配的 URL 之外的所有内容:
^/(?!bt/sub/(went_active|success|cancel|expired)).*$
据我所知,这应该匹配 http://local.mysite.com 中的 everything 并将其重定向到 https ://local.mysite.com,除了为以下四种:
http://local.mysite.com/bt/sub/went_active http://local.mysite.com/bt/sub/success http://local.mysite.com/bt/sub/cancel http://local.mysite.com/bt/sub/expired不过,Apache 会重定向所有内容,包括上述我不想重定向的 URL。
我在 SO 中发现了几个类似的问题,但大多数问题都是根据 mod_rewrite 来回答的,这不是我想要/需要的,而且人们说有用的那些对我没有用。
这是我目前的虚拟主机配置:
<VirtualHost *:80>
ServerName local.mysite.com
RedirectMatch 302 ^/(?!bt/sub/(went_active|success|cancel|expired)).*$ https://local.mysite.com
DocumentRoot /home/borfast/projects/www/mysite/public
#Header set Access-Control-Allow-Origin *
SetEnv LARAVEL_ENV localdev
<Directory /home/borfast/projects/www/mysite/public/>
Options All
DirectoryIndex index.php
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
请帮助并防止我发疯:)
更新: 发生了一些奇怪的事情:显然,当可以找到请求的 URL/路径时,Apache 会忽略 RedirectMatch 中的表达式并重定向客户端,即使 RedirectMatch 告诉它不要这样做。
为了测试这一点,我在一个单独的虚拟机中从头开始创建了一个新的虚拟主机,该虚拟机新安装了 Ubuntu Trussty 64,加载了 Apache 2.4。这个新的虚拟主机只包含 ServerName、RedirectMatch 和 DocumentRoot 指令,如下所示:
<VirtualHost *:80>
ServerName testing.com
RedirectMatch 302 ^/(?!bt/sub/(went_active|success)$).*$ https://othersite.com/
DocumentRoot /home/vagrant/www
</VirtualHost>
我创建了目录/home/vagrant/www/bt/sub/went_active
以确保 Apache 至少可以访问两个可能的 URL 之一。在尝试访问 http://testing.com:8080
时,我按预期被重定向。
然后奇怪的是:访问http://testing.com:8080/bt/sub/went_active
时,与我创建的目录匹配的URL,我仍然被重定向,即使我不应该,但是当访问http://testing.com:8080/bt/sub/success
时,我没有被重定向并且而是获得 403 Forbidden。
我可能对此失去了理智,但似乎当 Apache 发现它可以为请求提供服务并且它与 RedirectMatch 中应该阻止重定向的正则表达式匹配时,它决定忽略正则表达式并进行重定向.三个字母:WTF?!?!?!
【问题讨论】:
你的正则表达式匹配我的所有内容.*\.com\/foo\/bar\/(aaa|bbb|ccc|ddd) 我做了这个只匹配您不想替换的那些,如果您无法在代码中执行逻辑并需要它来匹配对立,只需将其设置为负前瞻或其他方式 无需转义/
这会更容易使用mod_rewrite
...
是的,但我明确表示我需要使用 mod_alias。如果人们不每年都买一部新手机,世界会更好,除此之外,还有很多事情是你无法改变的。 ;)
【参考方案1】:
正如在 cmets 中所说 - 使用 mod_rewrite
更容易。可能的解决方案
RewriteEngine On
RewriteCond %REQUEST_URI !^/bar/(abcd|baz|barista|yo)$ [NC]
RewriteRule ^ http://site/ [R=301,L]
另一个(对于 .htaccess,初始 /
已从 RewriteRule
中删除)
RewriteEngine On
RewriteRule !^bar/(abcd|baz|barista|yo)$ http://site/ [R=301,L,NC]
RedirectMatch
的解决方案
RedirectMatch permanent ^(?!/bar/(abcd|baz|barista|yo)$).* http://site/
一切正常,您在测试/调试状态下可能遇到的问题是浏览器缓存了301
响应。因此,当您尝试检查或编写正确的代码时 - 使用 302
响应,而不是 301
。如果不需要不区分大小写,请删除 NC
标志。
【讨论】:
我知道 mod_rewrite 会更容易,但我明确表示我需要使用 mod_alias。至于缓存,我考虑到这一点并尝试了几种不同的结尾(abcd、baz 等 - 每次都是新的),并监控 HTTP 请求以确保浏览器实际上获得了正确的重定向标头。 @borfast 我试过了,它可以工作(Ubuntu,Apache 2.4.7,都试过了)。这意味着您的问题不在这一行,而是在其他地方。没有足够的信息来准确判断它可能在哪里。 这几乎也是我要得出的结论。我刚刚用完整的虚拟主机配置更新了我的问题,以防有人可以在那里发现问题。 @borfast 您是否尝试将RedirectMatch
放入Directory
中?或者,至少在DocumentRoot
之后(不确定这是否重要,但更糟糕的是尝试)。我使用了.htaccess
,但也可以尝试在配置中进行测试。
以前没试过,现在才试,两种可能。甚至在另一个浏览器上尝试过。没有快乐。【参考方案2】:
见this one
^\/.*(?<!foo\/bar\/(aaa|bbb|ccc|ddd))$
匹配 / 后跟任何内容,除非字符串的结尾是 /foo/bar/(aaaa|bbb...)
(?<!
是附加到字符串结尾 $
的负向后视,它将检查它不可能匹配字符串结尾之前的内容。
如果您的真实案例不像您的示例那样静态,请为查询部分提供真实数据。
【讨论】:
Negative lookbehind 也应该起作用,并且也得到了在线正则表达式检查器的确认,但可惜,它不起作用。更具体地说,使用虚拟主机配置文件中的这一行:RedirectMatch 302 ^\/.*(?<!foo\/bar\/(aaa|bbb|ccc|ddd))$ https ://mysite.com
,我仍然会为每个 URL 重定向,包括 http://mysite.com/foo/bar/aaa(以及其他三个终止)。我的案例就是我描述的这个简单的案例。我希望每个 URL 都重定向到 HTTPS URL,除了这四个。不涉及查询,只是简单的 URL。起初看起来很简单......:|
我可能错了,但配置中还有其他涉及重定向的内容吗?我将不得不检查 apache 中的负前瞻和后视,您使用的是哪个版本?
糟糕,问题中的版本,我明天在 2.4 的 apache 上试试。
我不知道的有趣事实:lookbehinds 不适用于可变长度的交替。由于我的 URL 的结尾并不都具有相同的大小,因此向后查找可能不会奏效。该配置有一个ServerName
、一个DocumentRoot
和一个SetEnv
指令,以及一个<Directory>
部分,仅此而已。我正在评论它们,看看它是否有所作为。
注释掉文件中的其他设置使其工作。不知道为什么,我正在一一尝试以确定是什么造成了不同。 ----- 编辑:没关系,虚惊一场,是我愚蠢。以上是关于Apache mod_alias RedirectMatch 除特定模式外的所有内容的主要内容,如果未能解决你的问题,请参考以下文章