如果列表是有序的,anubhava 的答案比我的要好得多。如果不能保证列表是有序的,您可以使用以下规则。它使用了Jon Lin 在这个答案中使用的技术。
RewriteCond %{QUERY_STRING} ^(.*&|)(?!(phone|fax|zip))[^=]+=
RewriteCond ##%{QUERY_STRING} (.*?)##(|.*&)(phone)=([^&]+)
RewriteCond %1&%3=%4##%{QUERY_STRING} (.*?)##(|.*&)(fax)=([^&]+)
RewriteCond %1&%3=%4##%{QUERY_STRING} (.*?)##(|.*&)(zip)=([^&]+)
RewriteRule ^(.*)$ $1?%3=%4%1 [R,L]
那么,它有什么作用呢?第一个条件只有在可以找到不匹配的参数时才为真(phone|fax|zip)
(负前瞻)。接下来的三个RewriteCond
捕获您要保留的每个参数,并在自定义##
分隔符之前准备一个查询字符串。如果该分隔符恰好在您的查询字符串中,就会发生奇怪的事情。
这种方法的缺点是,如果这三个参数之一不存在,则不会应用该规则。我个人会将此白名单放在页面本身中,而不是尝试通过 .htaccess 对其进行过滤。
编辑:如果某些参数是可选的,您可以使用以下怪物:
RewriteCond %{QUERY_STRING} ^((.*?)&|)(?!(phone|fax|zip))[^=]+=[^&]+(&.*|)$
RewriteRule ^(.*)$ $1?%2%4 [R,E=Redir:1]
RewriteCond %{QUERY_STRING} ^&(.*)$
RewriteRule ^(.*)$ $1?%1 [R,E=Redir:1]
RewriteCond %{ENV:Redir} =1
RewriteRule ^ - [R,L]
基本上,如果字符串中的参数与前瞻中的参数不匹配,它将匹配该参数之前的部分和该参数后面的部分并重新生成查询字符串。第二条规则是如果第一个参数没有被“列入白名单”(或者它只是简单地以 & 开头),则防止它吞噬整个查询字符串,最后一条规则是尝试将重定向的数量保持在最低限度。请注意,如果请求中没有列入白名单的参数过多,浏览器会显示错误(检测到重定向链)。
相反,我建议对页面本身进行过滤。在 php 中,它将类似于以下代码。如果您决定使用其他 httpdeamon,这将使维护此白名单变得更容易,并且不会破坏一切。
<?php
$whitelist = Array( 'phone', 'fax', 'zip' );
foreach( $_GET as $k => $v ) {
if( !in_array( $k, $whitelist ) )
unset( $_GET[$k] );
}
#And the same for $_POST and $_REQUEST