【问题标题】:Remove all query strings except for those already rewritten删除除已重写的查询字符串之外的所有查询字符串
【发布时间】:2013-09-02 10:37:29
【问题描述】:

我已经将所有需要的查询字符串重写为对 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

但我想删除任何其他查询字符串,例如 item_123/?foo=bardatabase.php?foo=barpost_123/?type =product&id=321 出于 SEO 和安全原因。

明显明显的放置解决方案

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

在 .htaccess 的末尾处理之前没有处理过并被 [L] 标签停止的所有内容实际上破坏了原始 RewriteRule 并将 item_123/ 重定向到空的 数据库。 php 没有参数。

是否可以在不明确写下所有 %{REQUEST_URI}s 和 %{QUERY_STRING}s 对的异常的情况下删除所有查询字符串,但之前已经 mod_rewritten 的那些查询字符串除外?

编辑:

解决方案 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+,因此我使用了a workaround which would emulate this behaviour

# 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=bardatabase.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

accepted solution 中的代码本身是正确的,而我的版本扩展了重写以匹配许多其他格式错误的模式。

在上述所有代码之后从已接受的解决方案中添加代码将捕获(以前)未找到的 item_123/?foo=barcatalog/?foo=bar 模式的链接,并将它们 (301) 重定向到正确的 URL item_123/ 和 @987654349 @ 没有查询字符串。这是有道理的,因为即使用户遵循由某些 RSS 聚合器等修改的链接,用户也会到达他想要的地方。将%{QUERY_STRING} (.+) 更改为%{THE_REQUEST} ^GET\ [.?]+\? 以及在上述代码中使用%{THE_REQUEST} ^GET\ [^?]+$ 而不是%{QUERY_STRING} ^$ 也会删除尾随问号 - item_123/? - 否则会被忽略并算作重复页面。

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

【问题讨论】:

标签: php .htaccess mod-rewrite query-string


【解决方案1】:

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

【讨论】:

  • REQUEST_URI 中需要前面的斜杠才能使规则起作用 - RewriteCond %{REQUEST_URI} !^/[a-z]+\.php$ 除此之外,它完美地解释了它。由于不支持 [END] 标志,这正是我所需要的,因此不得不使用第一个选项加上一些巫术。
  • 啊,是的,请求 URI 通常在前面,有点疏忽。现在更正答案。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    您可以通过以下方式避免这种情况:

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

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

    【讨论】:

    • 这 a) 忽略查询 b) 允许重复页面,例如 item_123/abcditem_123/?foo=bar,而不是抛出 404 not found 或 301 重定向到 item_123/
    • 你确定吗?它重定向所有有效的item_([0-9]+)/ 并忽略 / 之后的所有内容
    • 它不会重定向([R=301,L] 会),它会重写(或者,好吧,内部重定向)路径。因此它为item_123/item_123/abcditem_123/?foo=bar 显示相同的内容,这不是所需的行为。换句话说,我想 摆脱 URL 中的 .* 部分,而不是 ignore 它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-25
    • 2016-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多