希望有人比我更擅长 htaccess RegEx!
我正在尝试替换(删除) URL 中的特定路径,但是我的规则似乎只想删除第一个文件夹,而不是整个路径。
这是我正在测试的规则,请注意,我为了调试而将反向引用重写到查询字符串中!
RewriteRule ^folder1/folder2/folder3/(.*)$ http://domain.com/?one=$1&two=$2 [L,NC,R=301]
因此,本质上我需要domain.com/folder1/folder2/folder3/?query=string
重定向到domain.com/?query=string
。
如果我可以保留路径的其余部分,那就是额外的好处,但也不会太在意,保留查询字符串是必须的。
问题是,根据上述规则,我得到了结果
domain.com/?one=folder2/folder3/folder2/folder3/&two=
正如您所看到的,它似乎接受了第一个目录匹配(从 folder1 开始),但随后它似乎采用了我想要删除的其余路径,复制它并将 ist 设置为第一个匹配的组!
这不是我想要的,我想匹配整个 3 个文件夹,删除它们并附加 URL 的其余部分,无论它是什么(查询字符串等)。
有人愿意纠正我吗? 可选地,了解我做错了什么会很有用,但不是必需的(借此机会加深我对 RegEx 的理解)
仅供参考:这些文件夹不存在,它们只是路由的路径。
提前致谢!
编辑:回复重复
该问题被标记为该常见(且最有价值)帖子的重复:在 Apache 中重定向、更改 URL 或将 HTTP 重定向到 HTTPS - 您想了解但又不敢问的有关 Mod_Rewrite 规则的一切
我已查看了这篇文章,但我看不出其中哪一部分涉及路径重写(因为我曾具体提出过疑问),也看不出其中哪一部分可以解释我得到的结果。因此,我将详细说明...
确实,很多例子都查看了更深层次的目录/路径,而不是更深层次的目录/路径,例如 sysadmin2218 中的这些:
RewriteRule ^/blog/([0-9]{4})/([-0-9a-zA-Z]*)\.html /newblog/$1/$2.shtml
RewriteRule ^/blog/([0-9]{4})/([-a-z]*)\.html /newblog/$1/$2.shtml
然而我没有经历过这种正确的匹配。这就是我的问题的本质尽管遵循了示例和手册页,但我似乎得到了意想不到的结果,因此我问了这个问题来确定我的错误在哪里。我可以阅读另外 20 篇 RewriteRule 帖子(自从我在发帖前阅读了大约 30 篇帖子以来),但我并没有更接近看到我的规则有什么问题。
如果有人能指出我的错误或增加我的理解,我会从中吸取教训并且不再问这个问题,但我似乎无法从互联网上的链接或其他帖子中找到答案。
我的简明案例 这是我当前情况的精确复制,首先这是我需要应用的规则:
- 所有规则均应用于公共域 (www.example.com)
- 如果键是 key1 或 key2,则从查询字符串中删除参数
- 将 www.example.com/oldfolder/* 重定向至 www.example.com/*
- 将 www.example.com/folder1/folder2/folder3/* 重定向到 www.example.com/newfolder/*
这是我目前的规则
# Activate Rewrite and set the base to the web path
RewriteEngine On
RewriteBase /
# Remove 'key1' from the Querystring, and remove any resulting double &'s
RewriteCond %{QUERY_STRING} (.*)(?:^|&)key1=(?:[^&]*)((?:&|$).*)
# %1 = any previous query string, %2 = any following query string
RewriteCond %1%2 (^|&)([^&].*|$)
# %1 = matched double & (disgard), %2 = the new query string
# $1 = non greedy match on the URI upto the last /
RewriteRule ^(.*)/$ $1?%2
#Remove 'key2' from the resulting URI, and remove double & again (as above)
RewriteCond %{QUERY_STRING} (.*)(?:^|&)key1=(?:[^&]*)((?:&|$).*)
RewriteCond %1%2 (^|&)([^&].*|$)
RewriteRule ^(.*)/$ $1?%2
#Catch and handle requests beginning with 'oldfolder'
#$1 = non greedy match everything following oldfolder
RewriteRule ^oldfolder(.*)$ $1 [L,NC,R=301]
#Catch the folder1/folder2/folder3 path and rewrite
RewriteRule ^folder1/folder2/folder3(.*)$ newfolder/$1 [L,NC,R=301]
好的,分解一下,查询字符串部分是 100%,而且第一个 RewriteRule 也很好,因为“oldfolder”已成功从 URI 中删除,其中包括清理后的查询字符串。
问题是最后一条规则,请考虑以下测试 URL
http://www.example.com/folder1/folder2/folder3/?key0=keep&key1=drop&key2=drop
这应该重写为
http://www.example.com/newfolder/?key0=keep
然而我得到的结果是
http://www.example.com/newfolder//folder2/folder3/folder2/folder3/?key0=keep
并非我所期望的那样,这是相关规则,以及我对预期结果的分析
RewriteRule ^folder1/folder2/folder3(.*)$ newfolder/$1 [L,NC,R=301]
因此,我们可以假设查询字符串已处理,对我而言,该模式表示匹配以 folder1/folder2/folder3 开头的 Web 路径(记住 RewriteBase / 有效),将剩余的 URI 分配给第一个组 ($1),即/?key0=keep
。那么模式将是 newfolder/?key0=keep。
然而,这不是我的经验...虽然查询字符串在我的结果中是正确的,但匹配似乎被吸收了folder2/folder3/
,复制了它,将它添加到查询字符串之前并继续进行......
我是 confuseed.com...(请帮忙!!)
答案1
好的,我追踪了我的问题,并且本着 Stack Exchange 的精神,我想分享我的答案。
我必须首先承认,我没有提到我使用的 Apache 版本,我使用的是 Apache 2.4。
事实证明,我被 Apache (2.2 -> 2.4) 中报告的一个错误所困扰,即Bug 38642 - mod_rewrite 在替换发生后添加路径信息后缀。
这个错误导致在进行替换时错误地添加路径,因此在我的每个影响查询字符串的 RewriteRules 之后,路径确实被重新附加。
据报道,该错误已在 Apache 2.5 中修复,并且有一个解决方法,即使用DPI 标志在重写规则中。
这使得我的例子如下:
# Activate Rewrite and set the base to the web path
RewriteEngine On
RewriteBase /
# Remove 'key1' from the Querystring, and remove any resulting double &'s
RewriteCond %{QUERY_STRING} (.*)(?:^|&)key1=(?:[^&]*)((?:&|$).*)
RewriteCond %1%2 (^|&)([^&].*|$)
RewriteRule ^(.*)/$ $1?%2 [DPI,E=querycleaned:1]
#Remove 'key2' from the resulting URI, and remove double & again
RewriteCond %{QUERY_STRING} (.*)(?:^|&)key2=(?:[^&]*)((?:&|$).*)
RewriteCond %1%2 (^|&)([^&].*|$)
RewriteRule ^(.*)/$ $1?%2 [DPI,E=querycleaned:1]
#Catch and handle requests beginning with 'oldfolder'
#$1 = non greedy match everything following oldfolder
RewriteRule ^oldfolder(.*)$ $1 [L,NC,R=301]
#Catch the folder1/folder2/folder3 path and rewrite
RewriteRule ^folder1/folder2/folder3(.*)$ newfolder$1 [L,NC,R=301]
#Catchall, if query string cleaned but not previously matched, then redirect to clean string
RewriteCond %{ENV:querycleaned} 1
RewriteRule ^(.*)$ $1 [L,R=301]
如您所见,DPI
任何可能产生更改但未标记为L
ast 的规则都会添加标志。
您可能还会注意到该E=querycleaned:1
标志。这只是设置一个环境变量以捕获所有内容,您会看到,如果以下重写规则之一匹配(以 oldfolder 或 folder1/folder2/folder3 开头),原始示例将清除查询字符串,但是无论如何我都希望清除查询字符串,所以基本上我设置了一个变量来指示查询是否已被清除,如果是,您会注意到底部的新捕获所有内容规则,它会重定向到现有路径,并带有干净的查询。
就这样,问题解决了。但公平地说,一旦我知道了答案,我就能在这里找到几个重复的问题,所以我不是第一个。我甚至无法在我的历史记录中找到我最先找到的问题,但快速搜索DPI
会得到一些结果。