单个URL的多个RewriteRules

时间:2016-08-11 09:57:52

标签: apache .htaccess mod-rewrite

我想在RewriteRules中使用多个.htaccess来修改单个网址,但只会应用最后一条规则。

示例INPUT(浏览器加载的链接):

http://example.com/aaa/foo/bar

htaccess的:

RewriteRule ^(.*)foo/(.*)$ $1nofoo/$2
RewriteRule ^(.*)bar(.*)$ $1nobar$2

预期输出(Apache应该实际看到的内容):

http://example.com/aaa/nofoo/nobar

实际输出:

http://example.com/aaa/foo/nobar/

如您所见,仅应用了最后一条规则。有没有办法让它按我想要的方式工作?欢迎提出所有建议。

PS。我想避免创建像

这样的静态丑陋规则
^(.*)foo/bar(.*) $1nofoo/nobar$2

我需要所有修改才能彼此独立工作。

更新

所以这正是我想要实现的目标。我有一些后端服务器的链接:

http://myserver.com/api/user/$userid/car/$carid/getSpeedRecordDetails
http://myserver.com/api/user/$userid/getUserDetails
http://myserver.com/api/car/$carid/getCarDetails

其中$ userid和$ carid是一些独特的12-char-long字符串。

我想把它们变成这些:

http://myserver.com/api/getSpeedRecordDetails.php?userid=$userid&carid=$carid
http://myserver.com/api/getUserDetails.php?userid=$userid
http://myserver.com/api/getCarDetails.php?carid=$carid

我想用尽可能少的RewriteRules来实现它(我正在寻找动态解决方案)。

更新#2

我喜欢SO社区!你的耐心和帮助的意愿确实令人惊叹:)

因此我有兴趣使用多个RewriteRules修改URL是因为我希望我的后端可能很快需要实现数百个(如果不是数千个)用户友好的URL,并且单独映射所有这些URL将是浪费时间和金钱。因此,我想利用这样一个事实:所有用户友好的URL都包含可以轻松翻译的重复块。下面的调用代表了我需要管理的一般三种类型的用户友好URL。每种类型的唯一区别是$ userid,$ carid和XXXX_of_a_thousand_functions。

http://myserver.com/backend-api/user/$userid/car/$carid/first_of_a_thousand_functions.do
http://myserver.com/backend-api/user/$userid/second_of_a_thousand_functions.do
http://myserver.com/backend-api/car/$carid/sixteenth_of_a_thousand_functions.do

所有这些电话(并且记住,将有数百个,甚至数千个)需要被翻译成这些:

http://myserver.com/backend-api/first_of_a_thousand_functions.php?USER_ID=$userid&CAR_ID=$carid
http://myserver.com/backend-api/second_of_a_thousand_functions.php?USER_ID=$userid
http://myserver.com/backend-api/sixteenth_of_a_thousand_functions.php?CAR_ID=$carid

看到有一个简单的模式来管理翻译(我希望你也可以看到它),我想我可以创建一些简单的规则来翻译不同的块'用户友好的URL到内部URL。例如:

RewriteRule ^(.*)user/([A-Za-z0-9]+)/(.*)$ $1$3&USER_ID=$2

负责将作品user/HSGRE8563LOS翻译成&USER_ID=HSGRE8563LOS

并且因为有些电话有多个电话'要处理,我需要能够在单个URL上使用多个RewriteRules,我希望这与问题的标题有些相关:)

更新#3 - 未来参考

因此,我认为需要就这个问题说几件事。

显然.htaccess DOES 默认情况下会应用符合条件的所有规则。但是,一些CGI / Fast-CGI安装会破坏它,导致第一个例子中描述的那种行为。

此外,我从未见过的任何地方提到的一点是,Apache不会按照RewriteRules中列出的顺序应用.htaccess,但它会开始扫描'从其开头的URL,以及满足任何规则的条件的基础,URL将相应地进行修改。

1 个答案:

答案 0 :(得分:1)

更新#1 ... 使用mod_rewrite从所述友好网址内部重写。在根.htaccess文件中尝试以下指令:

RewriteEngine On

# http://myserver.com/api/user/$userid/car/$carid/getSpeedRecordDetails
RewriteRule ^api/user/(\w{12})/car/(\w{12})/(getSpeedRecordDetails)$ /api/$3.php?userid=$1&carid=$2 [L]

# http://myserver.com/api/user/$userid/getUserDetails
RewriteRule ^api/user/(\w{12})/(getUserDetails)$ /api/$2.php?userid=$1 [L]

# http://myserver.com/api/car/$carid/getCarDetails
RewriteRule ^api/car/(\w{12})/(getCarDetails)$ /api/$2.php?carid=$1 [L]

\w{12}匹配12个字符长的字母串(上/下),数字和下划线。但是,这应该尽可能地限制。例如。如果有效的ID只是数字,那么\d{12}会更好。

更新#2 此过程几乎与上述相同....

RewriteBase /backend-api

# http://myserver.com/backend-api/user/$userid/car/$carid/<any>.do
RewriteRule ^backend-api/user/(\w{12})/car/(\w{12})/(\w+)\.do$ $3.php?USER_ID=$1&CAR_ID=$2 [L]

# http://myserver.com/backend-api/user/$userid/<any>.do
RewriteRule ^backend-api/user/(\w{12})/(\w+)\.do$ $2.php?USER_ID=$1 [L]

# http://myserver.com/backend-api/car/$carid/<any>.do
RewriteRule ^backend-api/car/(\w{12})/(\w+)\.do$ $2.php?CAR_ID=$1 [L]

请注意RewriteBase的使用。这样就可以从RewriteRule替换中删除网址路径。

如果/backend-api作为物理目录存在,则这些规则可以改为/backend-api/.htaccess。然后,您可以删除RewriteBase指令,并通过从模式开头附近删除RewriteRule部分来修改backend-api/ 模式

更新#3 - 未来参考

  

显然.htaccess DOES 默认情况下会应用符合条件的所有规则。但是,一些CGI / Fast-CGI安装会破坏它,导致第一个例子中描述的那种行为。

肯定有一些服务器(错误)配置似乎会影响.htaccess / mod_rewrite的某些方面,但是,不是你问题前面提到的方式,我自己从未直接遇到过这种情况。这应该与CGI / Fast-CGI无关。 (?)

  

... Apache不按照RewriteRules中列出的顺序应用.htaccess,...

不确定您的确切含义,但RewriteRules 处理&#34;按.htaccess&#34;中列出的顺序排列 - 这是mod_rewrite如何工作的基础。 (但是,不同的模块在不同时间执行,无论.htaccess中的顺序如何,但在每个模块中,指令按顺序自上而下执行。例如,mod_rewrite在mod_alias之前执行(通常),所以如果你在mod_rewrite Redirect之前有一个mod_alias RewriteRule,那么RewriteRule仍然会先被处理 - 这就是为什么混合来自两个模块的重定向是个不错的主意,因为你最终可能会出现令人困惑的冲突。)

  

...但它开始扫描&#39;从其开头的URL,以及满足任何规则的条件的基础,URL将相应地进行修改。

确切地说,按它们出现在文件中的顺序。

请注意,它是扫描的RewriteRule指令(自上而下),而不是条件(即RewriteCond指令) - 如果这是您所暗示的。如果RewriteRule 模式与URL路径匹配,则处理前面的RewriteCond指令,如果所有这些指令都通过则发生替换。 (这就是为什么将RewriteRuleRewriteCond完全匹配并且完全不依赖于RewriteRule指令更有效率 - 首先处理RewriteCond,而不是RewriteRule指令。)

至关重要的是,(这可能是你绊倒的地方?),如果你有多个RewriteRule指令,那么下面的RewriteRule指令与先前匹配的RewriteRule指令的输出/替换相匹配{1}}(如果有的话),不是针对初始请求的URL路径。只有第一个匹配的RewriteRule匹配请求的URL路径。所以,是的,L指令一起

例外情况是LAST上的RewriteRuleEND)标记。这&#34;休息&#34; 。虽然不是完全......它会导致当前一轮处理停止,但随后它会从顶部再次开始!仅当URL通过未更改时才处理完成。 (但是,在Apache 2.4中你确实有nmap --script ssl-enum-ciphers -p 443 google.com 标志 - 这确实完全停止了处理。)