当用户代理匹配 Twitter 或 Facebook 时,我想将 url 重定向到我的 ogp 页面。
我的重定向图片是这样的
/news/detail.html?id=1 -> /api/v1/informations/ogp/1?lang=ja
/news/detail.html?id=1&lang=en -> /api/v1/informations/ogp/1?lang=en
/sport/detail.html?id=1 -> /api/v1/sports/ogp/1?lang=ja
/sport/detail.html?id=1&lang=en -> /api/v1/sports/ogp/1?lang=en
/event/common/detail.html?id=1 -> /api/v1/events/ogp/1?lang=ja
/event/common/detail.html?id=1 -> /api/v1/events/ogp/1?lang=ja
/event/special/detail.html?id=2&lang=en -> /api/v1/events/ogp/2?lang=en
/event/special/detail.html?id=2 -> /api/v1/events/ogp/2?lang=ja
所以我写了 htaccess,Env params 工作正常,但是当 RewriteRule 超过两个或更多时,重写规则不起作用。
<IfModule mod_setenvif.c>
SetEnvIfNoCase User-Agent "^facebookexternalhit.*$" UA_FACEBOOK=1
SetEnvIfNoCase User-Agent "^facebookplatform.*$" UA_FACEBOOK=1
SetEnvIfNoCase User-Agent "^Twitterbot.*$" UA_TWITTER=1
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteCond %{ENV:UA_FACEBOOK} ^1$ [OR]
RewriteCond %{ENV:UA_TWITTER} ^1$
RewriteCond %{QUERY_STRING} (^|&)id=(\d+)&lang=(\w+)($|&)
RewriteRule ^news/detail.html$ /api/v1/informations/ogp/%2?lang=%3 [R,L]
RewriteRule ^sport/detail.html$ /api/v1/sports/ogp/%2?lang=%3 [R,L]
RewriteRule ^event/common/detail.html$ /api/v1/events/ogp/%2?lang=%3 [R,L]
RewriteRule ^event/special/detail.html$ /api/v1/events/ogp/%2?lang=%3 [R,L]
RewriteCond %{ENV:UA_FACEBOOK} ^1$ [OR]
RewriteCond %{ENV:UA_TWITTER} ^1$
RewriteCond %{QUERY_STRING} (^|&)id=(\d+)($|&)
RewriteRule ^news/detail.html$ /api/v1/informations/ogp/%2?lang=ja [R,L]
RewriteRule ^sport/detail.html$ /api/v1/sports/ogp/%2?lang=ja [R,L]
RewriteRule ^event/common/detail.html$ /api/v1/events/ogp/%2?lang=ja [R,L]
RewriteRule ^event/special/detail.html$ /api/v1/events/ogp/%2?lang=ja [R,L]
</IfModule>
我想用相同的 RewriteCond 重定向它们,该怎么做?
欢迎脏代码!
/news/detail.html?id=1 -> /api/v1/informations/ogp/1?lang=ja /news/detail.html?id=1&lang=en -> /api/v1/informations/ogp/1?lang=en /sport/detail.html?id=1 -> /api/v1/sports/ogp/1?lang=ja /sport/detail.html?id=1&lang=en -> /api/v1/sports/ogp/1?lang=en /event/common/detail.html?id=1 -> /api/v1/events/ogp/1?lang=ja /event/common/detail.html?id=1&lang=en -> /api/v1/events/ogp/1?lang=en /event/special/detail.html?id=2 -> /api/v1/events/ogp/2?lang=ja /event/special/detail.html?id=2&lang=en -> /api/v1/events/ogp/2?lang=en
这实际上只有 4 个 URL 映射(当
lang
参数被省略时,它分配了一个默认值 - 目标保持不变),所以你只需要 4 个规则(如果你提取 lang
参数)。最后 2 个重定向到同一个目标,因此可以轻松组合它们(使用正则表达式交替(common|special)
),只剩下 3 个需要的单独规则。
你可以这样做以避免任何重复:
RewriteEngine On
RewriteBase /api/v1
# Get "lang" (default to "ja")
RewriteRule ^ - [E=LANG:ja]
RewriteCond %{QUERY_STRING} (?:^|&)lang=(\w+)($|&)
RewriteRule ^ - [E=LANG:%1]
# Get "id" (if any)
RewriteCond %{QUERY_STRING} (?:^|&)id=(\d+)($|&)
RewriteRule ^ - [E=ID:%1]
# If not Facebook|Twitter OR no ID then skip the next 3 rules
RewriteCond %{HTTP_USER_AGENT} !^(facebook(externalhit|platform)|twitterbot) [NC,OR]
RewriteCond %{ENV:ID} ^$
RewriteRule ^ - [S=3]
# If here then Facebook|Twitter and "id" param are passed, LANG already set
RewriteRule ^news/detail\.html$ informations/ogp/%{ENV:ID}?lang=%{ENV:LANG} [R,L]
RewriteRule ^sport/detail\.html$ sports/ogp/%{ENV:ID}?lang=%{ENV:LANG} [R,L]
RewriteRule ^event/(common|special)/detail\.html$ events/ogp/%{ENV:ID}?lang=%{ENV:LANG} [R,L]
这里的技巧是使用
S
(skip
) 标志在用户代理是 not Facebook 或 Twitter 时跳过以下 3 条规则(或者没有 id
URL 参数存在)-颠倒逻辑。这意味着最后 3 条规则仅在 User-Agent is Facebook 或 Twitter 且 id
URL 参数存在时处理。
请注意,我使用了非捕获子模式来确保反向引用(即
%1
)仅引用我们感兴趣的组。
注意:我将
RewriteBase
更改为“简化”最后 3 条规则。尽管如果您有其他指令,那么您可能想要将其改回。
我尝试了使用If指令的方法,但是没有用
您当前的规则在
<If>
指令(Apache 2.4)中无法匹配,因为在此 context 中,RewriteRule
指令匹配绝对文件路径,而不是相对 URL 路径(可能是因为 <If>
容器合并非常晚)。
如果没有冲突,这里一个简单的解决方法是从
^
pattern的开头删除字符串开头锚点 (
RewriteRule
),以便能够匹配文件路径形式/absolute/file/path/to/public_html/news/detail.php
。 (虽然我可能会添加一个斜杠前缀以避免任何部分路径段匹配。)
所以,您可以这样写,而不是使用
<If>
表达式:
RewriteEngine On
# Get "id" (if any)
RewriteCond %{QUERY_STRING} (?:^|&)id=(\d+)($|&)
RewriteRule ^ - [E=ID:%1]
# Facebook|Twitter AND "id" param are passed
<If "%{HTTP_USER_AGENT} =~ /^(?i)(facebook(externalhit|platform)|twitterbot)/ && reqenv('ID') =~ /\d+/">
# Get "lang" (default to "ja")
RewriteRule ^ - [E=LANG:ja]
RewriteCond %{QUERY_STRING} (?:^|&)lang=(\w+)($|&)
RewriteRule ^ - [E=LANG:%1]
# Redirects
RewriteRule /news/detail\.html$ /api/v1/informations/ogp/%{ENV:ID}?lang=%{ENV:LANG} [R,L]
RewriteRule /sport/detail\.html$ /api/v1/sports/ogp/%{ENV:ID}?lang=%{ENV:LANG} [R,L]
RewriteRule /event/(common|special)/detail\.html$ /api/v1/events/ogp/%{ENV:ID}?lang=%{ENV:LANG} [R,L]
</If>
这段肮脏的代码做了我想要它做的事。
<IfModule mod_setenvif.c>
SetEnvIfNoCase User-Agent "^facebookexternalhit.*$" UA_FACEBOOK=1
SetEnvIfNoCase User-Agent "^facebookplatform.*$" UA_FACEBOOK=1
SetEnvIfNoCase User-Agent "^Twitterbot.*$" UA_TWITTER=1
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteCond %{ENV:UA_FACEBOOK} ^1$ [OR]
RewriteCond %{ENV:UA_TWITTER} ^1$
RewriteCond %{QUERY_STRING} (^|&)id=(\d+)&lang=(\w+)($|&)
RewriteRule ^news/detail.html$ /api/v1/informations/ogp/%2?lang=%3 [R,L]
RewriteCond %{ENV:UA_FACEBOOK} ^1$ [OR]
RewriteCond %{ENV:UA_TWITTER} ^1$
RewriteCond %{QUERY_STRING} (^|&)id=(\d+)&lang=(\w+)($|&)
RewriteRule ^sport/detail.html$ /api/v1/sports/ogp/%2?lang=%3 [R,L]
RewriteCond %{ENV:UA_FACEBOOK} ^1$ [OR]
RewriteCond %{ENV:UA_TWITTER} ^1$
RewriteCond %{QUERY_STRING} (^|&)id=(\d+)&lang=(\w+)($|&)
RewriteRule ^event/common/detail.html$ /api/v1/events/ogp/%2?lang=%3 [R,L]
RewriteCond %{ENV:UA_FACEBOOK} ^1$ [OR]
RewriteCond %{ENV:UA_TWITTER} ^1$
RewriteCond %{QUERY_STRING} (^|&)id=(\d+)&lang=(\w+)($|&)
RewriteRule ^event/special/detail.html$ /api/v1/events/ogp/%2?lang=%3 [R,L]
RewriteCond %{ENV:UA_FACEBOOK} ^1$ [OR]
RewriteCond %{ENV:UA_TWITTER} ^1$
RewriteCond %{QUERY_STRING} (^|&)id=(\d+)($|&)
RewriteRule ^news/detail.html$ /api/v1/informations/ogp/%2?lang=ja [R,L]
RewriteCond %{ENV:UA_FACEBOOK} ^1$ [OR]
RewriteCond %{ENV:UA_TWITTER} ^1$
RewriteCond %{QUERY_STRING} (^|&)id=(\d+)($|&)
RewriteRule ^sport/detail.html$ /api/v1/sports/ogp/%2?lang=ja [R,L]
RewriteCond %{ENV:UA_FACEBOOK} ^1$ [OR]
RewriteCond %{ENV:UA_TWITTER} ^1$
RewriteCond %{QUERY_STRING} (^|&)id=(\d+)($|&)
RewriteRule ^event/common/detail.html$ /api/v1/events/ogp/%2?lang=ja [R,L]
RewriteCond %{ENV:UA_FACEBOOK} ^1$ [OR]
RewriteCond %{ENV:UA_TWITTER} ^1$
RewriteCond %{QUERY_STRING} (^|&)id=(\d+)($|&)
RewriteRule ^event/special/detail.html$ /api/v1/events/ogp/%2?lang=ja [R,L]
</IfModule>
我尝试了使用 If 指令的方法,但它不适用于我的环境变量,如下面的代码
<If "%{ENV:UA_FACEBOOK} -eq 1 || %{ENV:UA_TWITTER} -eq 1"></If>
所以我通过一次又一次地编写很多相同的 RewriteCond 解决了这个问题。
如果你有更好的写法,我欢迎。