【问题标题】:Remove specific query string key/value pairs in htaccess (but leave others intact)删除 htaccess 中的特定查询字符串键/值对(但保留其他完整)
【发布时间】:2013-05-20 21:42:14
【问题描述】:

我想建立一个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/。我可能不知道要使用哪些查询字符串对,其中一些可能需要保留在查询字符串中以进行客户端处理。一些示例未知查询字符串键是;

  • gclid” - 由 Google Analytics (GA) 客户端脚本用于绑定 Adwords 数据
  • "utm_source" - 用于明确告诉 GA 流量来源/类型

【问题讨论】:

  • 作为一个花絮,检查参数可以稍微简化一点,如(?:^|&)a=([^&]+),您的非捕获开始或&符号仍然固定开始(避免xa = 123),但值可以是简单的非 & 号(将在下一个 & 号处停止,如果没有则运行到末尾)。
  • 我认为单独的规则是要走的路,但其中有很多。稍后我可以做一个具体的答案,但想法是:ab,ba,abe,cab,cadb,cabe,cadbe。可选捕获的问题是您最终会得到一个难以处理的“额外”&符号,因此特定的排列更容易(只是其中很多)。问题:是否总是有ab 参数(以任意顺序),或者可能有一个或另一个?
  • 我想我有一个解决方案。在 global.asax 的 Application_BeginRequest() 中(在 .htaccess 规则之前运行),我将检查各种动态页面的查询字符串变量是否按正确的顺序排列,然后让 .htaccess 使用一条规则进行处理。
  • 这一切都是因为我在 Google Analytics 中看到了 /path/foo/bar/ 和 /path/Default.aspx?a=foo&b=bar... 的不同页面记录/统计信息...同一页面,但后者不会重定向到前者(应该如此)
  • 使用代码而不是规则可能更容易。我似乎总是对 global.asax 有问题;如果是这样,您也可以在 default.aspx 中正确执行 - 如果 url 不正确,请修复并重定向。

标签: .htaccess mod-rewrite iis-7 isapi-rewrite


【解决方案1】:

我分两个阶段完成了这项工作。第一个是一组规则,提取一个参数,其他参数保持不变。然后我将其扩展为两个参数。规则本身并没有那么糟糕。只是很难弄清楚。

一个参数

这使用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。这确保这些仅在 ab 都存在时运行。如果只有一个或另一个存在,那么它会跳过所有这些。 (如果你打算只处理一个,这可以调整。)

# 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]


在代码中可能更容易......

【讨论】:

    【解决方案2】:

    这是一个有趣的!我的经验表明,有几个简单的条件比一个繁琐的规则要好。它通常更有效和高效。

    我的建议:

    # 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]
    

    这可能不像你想要的那样优雅,但它仍然可以解决问题。 我还可以想出更多的方法

    【讨论】:

    • 拆分成单独的规则是完全可以的。但是,在您的 a-b-c 对示例中,我从不尝试重定向到 /path/%1/%2/%3/ 。如果您包含“c”,我想直接指向 /path/%1/%2/?c=value 。关键是“c”的值需要在查询字符串中可供客户端解析......这可以是任意数量的键,例如:“gclid”(谷歌用于将 Adwords 信息传递给客户端分析脚本)或“utm_medium”(谷歌分析客户端脚本也用于处理媒体)
    • 您的代码似乎不起作用。 %1 表示第一个例子中 b 变量的值,第二个例子中 c 变量的值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-31
    • 2012-04-26
    • 1970-01-01
    • 2012-10-10
    • 2012-07-17
    • 1970-01-01
    • 2021-04-18
    相关资源
    最近更新 更多