如何将相同的RewriteCond附加到.htaccess中的不同RewriteRule?

发布于 2025-01-10 17:36:34 字数 2060 浏览 2 评论 0原文

当用户代理与 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 重定向它们,该怎么做?

即使是肮脏的代码也是受欢迎的!

I want to redirect url to my ogp page when User-agent matches Twitter or Facebook.

My redirect image is like this.

/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

So I wrote htaccess, Env params work ok, but rewrite rule does not work when RewriteRule takes two or more over.

<IfModule mod_setenvif.c>
    SetEnvIfNoCase User-Agent "^facebookexternalhit.*
quot; UA_FACEBOOK=1
    SetEnvIfNoCase User-Agent "^facebookplatform.*
quot; UA_FACEBOOK=1
    SetEnvIfNoCase User-Agent "^Twitterbot.*
quot; 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>

I want to redirect them all with same RewriteCond, how to do that?

Even dirty code is welcome!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

鲜肉鲜肉永远不皱 2025-01-17 17:36:34
/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) 标志来跳过以下 3 个规则,当用户代理不是 Facebook 或 Twitter(或者不存在 id URL 参数) - 反转逻辑。这意味着仅当用户代理是 Facebook 或 Twitter 并且存在 id URL 参数时,才会处理最后 3 条规则。

请注意,我使用非捕获子模式来确保反向引用(即 %1)仅引用我们感兴趣的组。

注意:我将 RewriteBase 更改为“简化”最后 3 条规则。不过,如果您有其他指令,那么您可能想将其改回来。

我尝试了使用If指令的方法,但没有成功

您当前的规则将无法在 指令 (Apache 2.4) 内匹配,因为在这个上下文中 RewriteRule 指令匹配绝对文件路径,而不是相对 URL 路径(可能是因为 容器被合并非常< /em> 晚了)。

如果不存在冲突,这里的一个简单解决方法是从 RewriteRule 模式的开头删除字符串开头锚点 (^) em> 以便能够匹配 /absolute/file/path/to/public_html/news/detail.php 形式的文件路径。 (尽管我可能会添加斜杠前缀以避免任何部分路径段匹配。)

因此,您可以像这样编写它,而不是使用 表达式:

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>
/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

This is really only 4 URL mappings (when the lang param is omitted it assigned a default - the target remains the same), so you only need 4 rules (if you extract the lang param). And the last 2 redirect to the same target so these can be easily combined (using regex alternation (common|special)), leaving just 3 separate rules that are required.

You could do it like this to avoid any repetition:

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]

The trick here is the use of the S (skip) flag to skip over the following 3 rules when the User-Agent is not Facebook or Twitter (or there is no id URL param present) - reversing the logic. Which means that the last 3 rules are only processed when the User-Agent is Facebook or Twitter and the id URL param is present.

Note that I used non-capturing subpatterns to ensure that the backreferences (ie. %1) only refer to the group we are interested in.

NB: I changed the RewriteBase to "simplify" the last 3 rules. Although if you have other directives then you may want to change this back.

I tried the method of using the If directive, but it didn't work

Your current rules would have failed to match inside an <If> directive (Apache 2.4), because in this context the RewriteRule directive matches against the absolute file-path, not a relative URL-path (probably because <If> containers are merged very late).

Providing there are no conflicts, a simple workaround here is to just remove the start-of-string anchor (^) from the start of the RewriteRule pattern so as to be able to match a file-path of the form /absolute/file/path/to/public_html/news/detail.php. (Although I would probably add a slash prefix in order to avoid any partial path-segment matches.)

So, you could potentially write it like this instead using an <If> expression:

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>
浪荡不羁 2025-01-17 17:36:34

这段肮脏的代码做了我想要它做的事情。

<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 解决了这个问题。

如果你有更好的写法,我欢迎。

This dirty code did what I wanted it to do.

<IfModule mod_setenvif.c>
    SetEnvIfNoCase User-Agent "^facebookexternalhit.*
quot; UA_FACEBOOK=1
    SetEnvIfNoCase User-Agent "^facebookplatform.*
quot; UA_FACEBOOK=1
    SetEnvIfNoCase User-Agent "^Twitterbot.*
quot; 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>

I tried the method of using the If directive, but it didn't work with my environment variable like below code

<If "%{ENV:UA_FACEBOOK} -eq 1 || %{ENV:UA_TWITTER} -eq 1"></If>

so I solved this problem by writing a lot of same RewriteCond again and again.

If you have a better way to write this, I welcome it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文