我想构建一个ISAPI_Rewrite 3 "RewriteRule来处理以下永久重定向:
╔════════════════════════════════╦════════════════════════════╗
║ Input ║ Redirect ║
╠════════════════════════════════╬════════════════════════════╣
║ /path/?a=foo&b=bar ║ /path/foo/bar/ ║
║ /path/?b=baz&a=qux ║ /path/qux/baz/ ║
║ /path/?c=1&a=foo&d=2&b=bar&e=3 ║ /path/foo/bar/?c=1&d=2&e=3 ║
╚════════════════════════════════╩════════════════════════════╝
例如;
RewriteCond ${QUERY_STRING} (?:^|&)a=([\w]+)(?:&|$)
RewriteCond ${QUERY_STRING} (?:^|&)b=([\w]+)(?:&|$)
RewriteRule ^/path/$ /path/%1/%2/? [R=301]
将起作用,除了它将剥离所有查询字符串对(第三个示例失败)。我似乎无法找到一个优雅的解决方案,只从URL中剥离已知的键/值对。等等...
RewriteCond ${QUERY_STRING} ^(.*)&?a=([\w]+)(.*)&?b=([\w]+)(.*)$
RewriteRule ^/path/$ /path/%2/%4/?%1%3%5 [R=301]
不完全正确(但你应该得到这个例子试图做的事情),并且匆忙得到真正的混乱。
有什么想法吗?
澄清:我的第三个示例,/path/?c=1&a=foo&d=2&b=bar&e=3
请求应重定向到/path/foo/bar/?c=1&d=2&e=3
而不是/path/foo/bar/1/2/3/
。我可能不知道将使用请求哪些查询字符串对,并且其中一些可能需要保留在查询字符串中以进行客户端处理。一些示例未知查询字符串键是;
答案 0 :(得分:2)
我分两个阶段做到了这一点。第一个是一组规则,它们提取一个参数,而其他参数保持原样。然后我将其扩展为两个参数。规则本身并不坏;这很难搞清楚。
一个参数
这使用示例的a
参数。有4个条件:
由于问号与&符号,最简单的做单独的规则。事实证明,最后两个很容易合并为一个规则。
(注意:我正在使用Helicon Ape重写,它通常与Apache兼容。我有一个问题,RewriteRule问号需要在参数之前转义,例如\?%2
。我不知道如果这一般是正确的。)
# a
# ?a=foo
# Starts with a=, non-ampersand to the end.
# Suppress querystring with trailing question mark.
RewriteCond ${QUERY_STRING} ^a=([^&]+)$
RewriteRule ^/path/$ /path/%1/? [NC,R=301,L]
# a-other
# ?a=foo&b=bar, ?a=foo&b=bar&c=1
# Starts with a=, non-ampersand, ampersand, remaining required.
# Escape question mark so it doesn't include entire original querystring.
RewriteCond ${QUERY_STRING} ^a=([^&]+)&(.+)
RewriteRule ^/path/$ /path/%1/\?%2 [NC,R=301,L]
# other-a or other-a-other
# ?b=baz&a=qux, ?b=baz&c=1&a=qux
# ?c=1&a=foo&d=2&b=bar&e=3, ?z=4&c=1&a=foo&d=2&b=bar&e=3
# Starts with anything, ampersand, a=, non-ampersand, remaining optional.
# The remaining optional lets it follow with nothing, or with ampersand and more parameters.
# Escape question mark so it doesn't include entire original querystring.
RewriteCond ${QUERY_STRING} ^(.+)&a=([^&]+)(.*)$
RewriteRule ^/path/$ /path/$2/\?%1%3 [NC,R=301,L]
两个参数
将这两个参数放在一起有点棘手,但想法是重写a
,然后重写b
并重定向。要同时管理这两个部分,请将path
重写为temppath
,然后重写temppath2
,然后在完成时将其重写为path
。这可确保仅在a
和b
都存在时才会运行这些内容。如果只有一个或另一个存在,那么它会跳过这一切。 (如果你打算也只处理一个,可以调整它。)
# Test cases:
# 1) /path/?a=foo&b=bar to /path/foo/bar
# 2) /path/?a=foo&b=bar&c=1 to /path/foo/bar?c=1
# 3) /path/?a=foo&b=bar&c=1&d=2 to /path/foo/bar?c=1&d=2
# 4) /path/?b=baz&a=qux to /path/qux/baz
# 5) /path/?b=baz&c=1&a=qux to /path/qux/baz/?c=1
# 6) /path/?c=1&b=baz&a=qux to /path/qux/baz/?c=1
# 7) /path/?c=1&d=2&b=baz&a=qux to path/qux/baz/?c=1&d=2
# 8) /path/?c=1&a=foo&d=2&b=bar&e=3 to /path/foo/bar/?c=1&d=2&e=3
# 9) /path/?z=4&c=1&a=foo&d=2&b=bar&e=3 to /path/foo/bar/?z=4&c=1&d=2&e=3
# Check for a and b (or b and a), rewrite to temp path and continue.
RewriteCond ${QUERY_STRING} (?:^|&)(?:a|b)=.+&(?:b|a)=.+$
RewriteRule ^/path/$ /temppath/ [NC]
# a
# ?a=foo
# This case isn't needed, since we test for a and b above.
# a-other
# 1) /temppath/?a=foo&b=bar to /temppath2/foo/?b=bar
# 2) /temppath/?a=foo&b=bar&c=1 to /temppath2/foo/?b=bar&c=1
# 3) /temppath/?a=foo&b=bar&c=1&d=2 to /temppath2/foo/?b=bar&c=1&d=2
# Starts with a=, non-ampersand, ampersand, remaining required.
RewriteCond ${QUERY_STRING} ^a=([^&]+)&(.+)$
RewriteRule ^/temppath/$ /temppath2/%1/\?%2 [NC]
# other-a or other-a-other
# 4) /temppath/?b=baz&a=qux to /temppath2/qux/?b=baz
# 5) /temppath/?b=baz&c=1&a=qux to /temppath2/qux/?b=baz&c=1
# 6) /temppath/?c=1&b=baz&a=qux to /temppath2/qux/?c=1&b=baz
# 7) /temppath/?c=1&d=2&b=baz&a=qux to /temppath2/qux/?c=1&d=2&b=baz
# 8) /temppath/?c=1&a=foo&d=2&b=bar&e=3 to /temppath2/foo/?c=1&d=2&b=bar&e=3
# 9) /temppath/?z=4&c=1&a=foo&d=2&b=bar&e=3 to /temppath2/foo/?z=4&c=1&d=2&b=bar&e=3
# Starts with anything, ampersand, a=, non-ampersand, remaining optional.
# The remaining optional lets it follow with nothing, or with ampersand and more parameters.
# Escape question mark so it doesn't include entire original querystring.
RewriteCond ${QUERY_STRING} ^(.+)&a=([^&]+)(.*)$
RewriteRule ^/temppath/$ /temppath2/%2/\?%1%3 [NC]
# b
# 1) /temppath2/foo/?b=bar to /path/foo/bar
# 4) /temppath2/qux/?b=baz to /path/qux/baz
# Starts with b=, non-ampersand to the end.
# Capture and use path after temppath2, since it has the a folder from above.
RewriteCond ${QUERY_STRING} ^b=([^&]+)$
RewriteRule ^/temppath2/(.*)/$ /path/$1/%1/? [NC,R=301,L]
# b-other
# 2) /temppath2/foo/?b=bar&c=1 to /path/foo/bar?c=1
# 3) /temppath2/foo/?b=bar&c=1&d=2 to /path/foo/bar?c=1&d=2
# 5) /temppath2/qux/?b=baz&c=1 to /path/qux/baz/?c=1
# Starts with b=, non-ampersand, ampersand, remaining required.
# Capture and use path after temppath2, since it has the a folder from above.
# Escape question mark so it doesn't include entire original querystring.
RewriteCond ${QUERY_STRING} ^b=([^&]+)&(.+)$
RewriteRule ^/temppath2/(.*)/$ /path/$1/%1/\?%2 [NC,R=301,L]
# other-b or other-b-other
# 6) /temppath2/qux/?c=1&b=baz to /path/qux/baz/?c=1
# 7) /temppath2/qux/?c=1&d=2&b=baz to /path/qux/baz/?c=1&d=2
# 8) /temppath2/foo/?c=1&d=2&b=bar&e=3 to /path/foo/bar/?c=1&d=2&e=3
# 9) /temppath2/foo/?z=4&c=1&d=2&b=bar&e=3 to /path/foo/bar/?z=4&c=1&d=2&e=3
# Starts with anything, ampersand, b=, non-ampersand, remaining optional.
# The remaining optional lets it follow with nothing, or with ampersand and more parameters.
# Capture and use path after temppath2, since it has the a folder from above.
# Escape question mark so it doesn't include entire original querystring.
RewriteCond ${QUERY_STRING} ^(.+)&b=([^&]+)(.*)$
RewriteRule ^/temppath2/(.*)/$ /path/$1/%2/\?%1%3 [NC,R=301,L]
代码可能更容易....
答案 1 :(得分:0)
这是一个有趣的!我的经验表明,有一个简单的条件比一个繁琐的规则更好。它通常更有效率。
我的建议:
# a-b pair
RewriteCond %{QUERY_STRING} a=([^&]+)
RewriteCond %{QUERY_STRING} b=([^&]+)
RewriteRule ^/path/$ /path/%1/%2/? [NC,R=301,L]
# a-b-c pair
RewriteCond %{QUERY_STRING} a=([^&]+)
RewriteCond %{QUERY_STRING} b=([^&]+)
RewriteCond %{QUERY_STRING} c=([^&]+)
RewriteRule ^/path/$ /path/%1/%2/%3/? [NC,R=301,L]
这可能不如你想要的那么优雅,但它应该仍然可以解决问题。 我还可以提出更多方法