htaccess RewriteRule 用于多个文件或路径

htaccess RewriteRule 用于多个文件或路径

希望有人比我更擅长 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任何可能产生更改但未标记为Last 的规则都会添加标志。

您可能还会注意到该E=querycleaned:1标志。这只是设置一个环境变量以捕获所有内容,您会看到,如果以下重写规则之一匹配(以 oldfolder 或 folder1/folder2/folder3 开头),原始示例将清除查询字符串,但是无论如何我都希望清除查询字符串,所以基本上我设置了一个变量来指示查询是否已被清除,如果是,您会注意到底部的新捕获所有内容规则,它会重定向到现有路径,并带有干净的查询。

就这样,问题解决了。但公平地说,一旦我知道了答案,我就能在这里找到几个重复的问题,所以我不是第一个。我甚至无法在我的历史记录中找到我最先找到的问题,但快速搜索DPI会得到一些结果。

相关内容