我有所有需要重写为 SEO 友好 URL 的查询字符串,例如
RewriteRule ^item_([0-9]+)/$ database.php?type=product&id=$1 [L]
RewriteRule ^post_([0-9]+)/$ articles.php?id=$1 [L]
... and so on
但出于 SEO 和安全原因,我想删除任何其他查询字符串,如item_123/?foo=bar或database.php?foo=bar或post_123/?type=product&id=321 。
放置的明显明显的解决方案
RewriteCond %{QUERY_STRING} (.+)
RewriteRule (.*) http://www.example.com/$1? [R=301,L]
在 .htaccess 末尾处理之前没有处理过并被 [L] 标签停止的所有内容实际上破坏了原始 RewriteRule 并将item_123/重定向到没有参数的空database.php。
是否可以删除所有查询字符串,除了之前已经 mod_rewritten 的那些查询字符串,而无需明确写下所有 %{REQUEST_URI}s 和 %{QUERY_STRING}s 对的异常?
编辑:
解决方案 A
# You do not need this whole block if you're running Apache v2.3.9+
RequestHeader set SOME-FANCY-NAME-FOR-THE-HEADER-AS-DESCRIBED-IN-THE-ABOVE-LINK 1 env=END
RewriteCond %{HTTP:SOME-FANCY-NAME-FOR-THE-HEADER-AS-DESCRIBED-IN-THE-ABOVE-LINK} =1 [NV]
RewriteRule .* - [L]
由于该[END]
标志仅适用于 Apache v2.3.9+,因此我使用了一种可以模拟此行为的解决方法。
# Replace [L,E=END:1] with [END] if running Apache v2.3.9+
RewriteCond %{THE_REQUEST} ^GET\ [^?]+$
RewriteRule ^item_([0-9]+)/$ database.php?type=product&id=$1 [L,E=END:1]
首先简单地限制?
THE_REQUEST 中的任何内容将导致item_123/?foo=bar
找不到重复的模式页面 (404)。该[L,E=END:1]
标志告诉 mod_rewrite 停止当前迭代并重复;下一次迭代将触发RewriteRule .* - [L]
并阻止它到达我们之后的潜在循环。如果支持该[END]
标志,它将立即停止它。
RewriteCond %{QUERY_STRING} type=product
RewriteCond %{QUERY_STRING} id=([0-9]+)
RewriteRule ^database\.php$ http://www.example.com/item_%1/? [R=301,L]
这还将重定向 (301) 可能受损的重复database.php?type=product&foo=bar&id=123
模式页面到正确的 URL,而不管查询中的乱码参数。一旦到达正确的 URL,它就会停在那里而不会导致循环和错误 500。
# If page is accessible without parameters
RewriteCond %{THE_REQUEST} ^GET\ [^?]+$
RewriteRule ^catalog/$ database.php [L,E=END:1]
RewriteCond %{THE_REQUEST} ^GET\ [^?]+\?
RewriteRule ^database\.php$ http://www.example.com/catalog/? [R=301,L]
如果页面可以在没有上述参数的情况下访问?type
,&type
但作为database.php?foo=bar
or访问database.php?
,它将被重定向 (301) 到catalog/
没有查询字符串。catalog/?foo=bar
同样,将找不到一页图案(404)。
# If page is not accessible without parameters
RewriteCond %{THE_REQUEST} ^GET\ [^?]+\?
RewriteRule ^database(\.php|/)?$ database.php [L,E=END:1]
如果页面在没有参数的情况下无法访问,我们可以强制停止重写(以避免以后不必要的重定向,例如我们已经anyotherfile.php
重写到anyotherfile/
),并在知道没有传递有效参数时让页面自己发送 404 标头。
解决方案 A+B
接受的解决方案中的代码本身是正确的,而我的版本扩展了重写以匹配许多其他格式错误的模式。
在上述所有代码之后添加来自已接受解决方案的代码将捕获(以前)未找到的链接item_123/?foo=bar
和catalog/?foo=bar
模式,并将它们(301)重定向到正确的 URLitem_123/
并且catalog/
没有查询字符串。这是有道理的,因为即使用户遵循由某些 RSS 聚合器等修改的链接,用户也会到达他想要的地方。在上面的代码中更改%{QUERY_STRING} (.+)
为%{THE_REQUEST} ^GET\ [.?]+\?
using%{THE_REQUEST} ^GET\ [^?]+$
而不是%{QUERY_STRING} ^$
也会删除尾随问号 -item_123/?
否则会被忽略并在处理时被视为重复页面。
RewriteCond %{THE_REQUEST} ^GET\ [^?]+\?
RewriteRule (.*) http://www.example.com/$1? [R=301,L]