【问题标题】:How to reorder URL parameters / query string using Apache htaccess?如何使用 Apache htaccess 重新排序 URL 参数/查询字符串?
【发布时间】:2021-01-05 17:08:48
【问题描述】:

我有带有分面导航(过滤)的电子商务类别。过滤可以生成数千个(有用的)URL。我想减少nr。通过始终在具有相同查询字符串参数顺序的相同 URL 上显示某些内容来增加可能的 URL。

从 SEO 的角度来看,我可以使用规范标签从逻辑上消除重复的 URL,但从性能的角度来看,使用 RewriteRules 解决它会更好。

内容相同但参数顺序不同的 URL 示例:

  • https://example.com/category/subcategory/?filter_manuf=grohe&filter_style=design&filter_family=bauedge&filter_warranty=5y
  • https://example.com/category/subcategory/?filter_style=design&filter_manuf=grohe&filter_warranty=5y&filter_family=bauedge

应将这些 URL 重定向到查询参数始终以相同顺序出现的 URL。 例如:

https://example.com/category/subcategory/?filter_manuf=grohe&filter_family=bauedge&filter_style=design&filter_warranty=5y

注意:

  • 我有超过 10 个过滤条件(查询参数)
  • 参数顺序根据用户的过滤器选择顺序而变化。它们可以按任何给定顺序出现。
  • 只有使用的参数才会出现在 URL 中。有些网页的网址中有一个或两个参数,有些则多达十个或更多。

您知道如何实现吗?

我在这个问题中发现了一些有希望的东西,但我无法让它发挥作用:
RewriteCond to match query string parameters in any order

【问题讨论】:

  • "从性能的角度来看,使用 RewriteRules 解决它会好得多。" - 不,它不会。这应该在您构建 URL 时在您的应用程序中解决。
  • 您好 MrWhite,您是指何时构建分面导航链接?是的,我也想到了这个想法。通过这样做并向所有页面添加 Canonical 标签 也可以解决此问题。我认为可以使用重写规则来做到这一点,但这似乎不可行。谢谢。
  • 是的,在您构建规范标签时,是否也将其用作可见 URL?使用 mod_rewrite 执行此操作在技术上是可行的,但效率低下(且复杂)。如果用户碰巧遵循了不正确的入站链接,您只想“重定向”用户。该链接的问题承认它不是一个有效的示例(它有许多语法错误)。但它也忽略了一些重要的细节,比如检查 URL 参数是否已经按正确的顺序排列(它使用不同的 URL 路径来避免这个问题)。这是一个有趣的问题,但不是特别实用。

标签: apache .htaccess redirect mod-rewrite query-string


【解决方案1】:

但从性能的角度来看,使用 RewriteRules 解决它会好得多。

性能的角度来看,最好在您的应用程序中解决这个问题,而不是.htaccess/mod_rewrite(即RewriteRules)。您希望始终正确链接到规范 URL。

您当然不希望在用户应用过滤器以“更正” URL 参数顺序时从外部重定向用户。 URL 参数应该以“正确”的形式应用到您的应用程序开始。

唯一有益于“重定向”用户的情况是,如果他们关注了第三方非规范链接(来自其他网站或搜索引擎)并且您需要解决潜在的 SEO 问题。但即便如此,如果作为应用程序逻辑的一部分而不是.htaccess 来实现,更正 URL 参数顺序的代码应该会简单得多(并且更易于维护)。在.htaccess 中执行此操作的代码相对更“复杂”(阅读:混乱、可能更难维护、更容易出错等)

但是,这是一个有趣的问题,当您无法在应用程序中轻松执行此操作时,可能会更可取(或有必要)在 .htaccess(或 Apache 服务器配置)中编写此代码。

.htaccess(或服务器配置)中使用 mod_rewrite 的解决方案

(但是,请注意上面的 cmets - 这可能不是您应该做的。)

这是一个相当通用的解决方案,适用于.htaccess(或服务器配置)。就目前而言,它适用于 any URL 路径。要使其在单个 URL 路径上工作(例如,/category/subcategory/,如问题中所述),然后修改最终 RewriteRule 指令中的 pattern。例如:

RewriteRule ^category/subcategory/$ %{REQUEST_URI}?%{ENV:NEW_QUERY_STRING} [NE,R=302,L]

或者,如果您需要将其应用于一组 URL 而不是其他 URL,您可以在顶部编写一个例外以跳过某些 URL 的这些规则。这可能更优化,因为它避免了对查询字符串的任何不必要的处理。

此代码块需要靠近您的 .htaccess 文件的顶部。 (顺序很重要。)

此代码具有额外的“好处”,它还通过删除任何未定义的 URL 参数(在脚本顶部)来“清理”查询字符串。

由于“简单地”确定原始 URL 参数是否已按正确顺序排列并非易事,因此脚本会按照正确顺序执行使用 URL 参数构造新查询字符串的过程,然后将其与原始查询字符串,以确定是否需要重定向。

标准:

  • 最多 10 个网址参数
  • 任意数量的 URL 参数可以按任意顺序出现
  • 不应包含空 URL 参数
  • URL 参数区分大小写
  • 适用于任何 URL 路径
  • URL 参数名称匹配正则表达式[\w-]+(即a-zA-Z0-9_-
  • URL 参数值不能包含@(除非 URL 编码)
  • @@@ 不能出现在查询字符串中的任何位置

您只需按照您希望的顺序在脚本顶部定义 URL 参数名称。它们保存在环境变量VAR_NAME_01VAR_NAME_02 等中。脚本的其余部分应保持不变,除非:

  • 您需要添加更多网址参数
  • 或者,更改内部用于分隔模式匹配部分的字符(当前为“@”)。
  • 或者,将代码限制为特定的 URL 路径。

脚本:

# Define the "name" of each URL parameter
# The numeric order determines the order of the resulting URL parameter list.
# Comment out any URL parameters that are not required.
SetEnvIf ^ ^ VAR_NAME_01=one
SetEnvIf ^ ^ VAR_NAME_02=two
SetEnvIf ^ ^ VAR_NAME_03=three
SetEnvIf ^ ^ VAR_NAME_04=four
SetEnvIf ^ ^ VAR_NAME_05=five
SetEnvIf ^ ^ VAR_NAME_06=six
SetEnvIf ^ ^ VAR_NAME_07=seven
SetEnvIf ^ ^ VAR_NAME_08=eight
SetEnvIf ^ ^ VAR_NAME_09=nine
SetEnvIf ^ ^ VAR_NAME_10=ten

###############################################################################
# Shouldn't need to modify directives below here...

RewriteEngine on
Options +FollowSymLinks

# -----------------------------------------------------------------------------
# Read each URL parameter (if any) and store in corresponding env var

RewriteCond %{QUERY_STRING}@%{ENV:VAR_NAME_01} (?:^|&)([\w-]+)=([^&@]+).*@\1
RewriteRule ^ - [E=VAR_VALUE_01:%2]

RewriteCond %{QUERY_STRING}@%{ENV:VAR_NAME_02} (?:^|&)([\w-]+)=([^&@]+).*@\1
RewriteRule ^ - [E=VAR_VALUE_02:%2]

RewriteCond %{QUERY_STRING}@%{ENV:VAR_NAME_03} (?:^|&)([\w-]+)=([^&@]+).*@\1
RewriteRule ^ - [E=VAR_VALUE_03:%2]

RewriteCond %{QUERY_STRING}@%{ENV:VAR_NAME_04} (?:^|&)([\w-]+)=([^&@]+).*@\1
RewriteRule ^ - [E=VAR_VALUE_04:%2]

RewriteCond %{QUERY_STRING}@%{ENV:VAR_NAME_05} (?:^|&)([\w-]+)=([^&@]+).*@\1
RewriteRule ^ - [E=VAR_VALUE_05:%2]

RewriteCond %{QUERY_STRING}@%{ENV:VAR_NAME_06} (?:^|&)([\w-]+)=([^&@]+).*@\1
RewriteRule ^ - [E=VAR_VALUE_06:%2]

RewriteCond %{QUERY_STRING}@%{ENV:VAR_NAME_07} (?:^|&)([\w-]+)=([^&@]+).*@\1
RewriteRule ^ - [E=VAR_VALUE_07:%2]

RewriteCond %{QUERY_STRING}@%{ENV:VAR_NAME_08} (?:^|&)([\w-]+)=([^&@]+).*@\1
RewriteRule ^ - [E=VAR_VALUE_08:%2]

RewriteCond %{QUERY_STRING}@%{ENV:VAR_NAME_09} (?:^|&)([\w-]+)=([^&@]+).*@\1
RewriteRule ^ - [E=VAR_VALUE_09:%2]

RewriteCond %{QUERY_STRING}@%{ENV:VAR_NAME_10} (?:^|&)([\w-]+)=([^&@]+).*@\1
RewriteRule ^ - [E=VAR_VALUE_10:%2]

# -----------------------------------------------------------------------------
# Construct new query string
# Only with URL parameters that are not empty

RewriteCond %{ENV:VAR_VALUE_01} .
RewriteRule ^ - [E=NEW_QUERY_STRING:%{ENV:VAR_NAME_01}=%{ENV:VAR_VALUE_01}]

RewriteCond %{ENV:VAR_VALUE_02} .
RewriteRule ^ - [E=NEW_QUERY_STRING:%{ENV:NEW_QUERY_STRING}&%{ENV:VAR_NAME_02}=%{ENV:VAR_VALUE_02}]

RewriteCond %{ENV:VAR_VALUE_03} .
RewriteRule ^ - [E=NEW_QUERY_STRING:%{ENV:NEW_QUERY_STRING}&%{ENV:VAR_NAME_03}=%{ENV:VAR_VALUE_03}]

RewriteCond %{ENV:VAR_VALUE_04} .
RewriteRule ^ - [E=NEW_QUERY_STRING:%{ENV:NEW_QUERY_STRING}&%{ENV:VAR_NAME_04}=%{ENV:VAR_VALUE_04}]

RewriteCond %{ENV:VAR_VALUE_05} .
RewriteRule ^ - [E=NEW_QUERY_STRING:%{ENV:NEW_QUERY_STRING}&%{ENV:VAR_NAME_05}=%{ENV:VAR_VALUE_05}]

RewriteCond %{ENV:VAR_VALUE_06} .
RewriteRule ^ - [E=NEW_QUERY_STRING:%{ENV:NEW_QUERY_STRING}&%{ENV:VAR_NAME_06}=%{ENV:VAR_VALUE_06}]

RewriteCond %{ENV:VAR_VALUE_07} .
RewriteRule ^ - [E=NEW_QUERY_STRING:%{ENV:NEW_QUERY_STRING}&%{ENV:VAR_NAME_07}=%{ENV:VAR_VALUE_07}]

RewriteCond %{ENV:VAR_VALUE_08} .
RewriteRule ^ - [E=NEW_QUERY_STRING:%{ENV:NEW_QUERY_STRING}&%{ENV:VAR_NAME_08}=%{ENV:VAR_VALUE_08}]

RewriteCond %{ENV:VAR_VALUE_09} .
RewriteRule ^ - [E=NEW_QUERY_STRING:%{ENV:NEW_QUERY_STRING}&%{ENV:VAR_NAME_09}=%{ENV:VAR_VALUE_09}]

RewriteCond %{ENV:VAR_VALUE_10} .
RewriteRule ^ - [E=NEW_QUERY_STRING:%{ENV:NEW_QUERY_STRING}&%{ENV:VAR_NAME_10}=%{ENV:VAR_VALUE_10}]

# -----------------------------------------------------------------------------
# Trim "&" prefix from the NEW_QUERY_STRING
RewriteCond %{ENV:NEW_QUERY_STRING} ^&(.+)
RewriteRule ^ - [E=NEW_QUERY_STRING:%1]

# Compare with existing QUERY_STRING to determine whether it's in the correct order already
# If different then redirect...
RewriteCond %{QUERY_STRING}@@@%{ENV:NEW_QUERY_STRING} !^(.+)@@@\1
RewriteRule ^ %{REQUEST_URI}?%{ENV:NEW_QUERY_STRING} [NE,R=302,L]

如果您对此脚本的特定部分有任何疑问,请在 cmets 中说...

【讨论】:

    猜你喜欢
    • 2015-04-27
    • 2012-11-15
    • 1970-01-01
    • 1970-01-01
    • 2021-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-05
    相关资源
    最近更新 更多