1

我有所有需要重写为 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=bardatabase.php?foo=barpost_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=baror访问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=barcatalog/?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]
4

3 回答 3

2

L 标志不会停止。如果您更改了 URL(您做了),它会重新注入。因此,对于您所做的每个内部重定向(重写),最后一个条件都可以,然后触发最后一个重写:

RewriteCond %{QUERY_STRING} (.+)
RewriteRule (.*) http://www.example.com/$1? [R=301,L]

由于这个确实删除了查询字符串(以 结尾?,没有QSA标志),因此您以不带参数的 php 脚本结尾:

rewrite #1/1: item_5/ -> database.php?type=product&id=5
              L triggered, because URL changed, re-inject:
rewrite #1/2: database.php?type=product&id=5 -> http://www.example.com/database.php?
              R triggered, exiting

rewrite #2/1: http://www.example.com/database.php? -
              no rule matches, use as-is

相反,您需要在末尾放置一个条件以不重定向 .php 文件:

RewriteCond %{QUERY_STRING} (.+)
RewriteCond %{REQUEST_URI} !^/[a-z]+\.php$    
RewriteRule (.*) http://www.example.com/$1? [R=301,L]

或者,如果您有更现代的 apache 服务器版本,只需使用以下END标志:

RewriteRule ^item_([0-9]+)/$ database.php?type=product&id=$1 [END]
RewriteRule ^post_([0-9]+)/$ articles.php?id=$1 [END]
... and so on
于 2013-08-29T20:42:11.803 回答
0

您可以使用以下方法避免这种情况:

RewriteRule ^item_([0-9]+)/.*$ abc.php?type=product&id=$1 [L]

.*在斜线之后添加了匹配任何内容,但它仍然是您重定向的有效模式。

于 2013-08-29T20:41:33.867 回答
0

我不知道这是否有帮助,但我处理事情的方式是将不存在的文件发送到特定的 php 文件(rewrite.php)

RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^.*$ ./rewrite.php

这让我可以轻松处理我遇到的每一个案例

于 2013-08-29T20:38:47.943 回答