但从性能的角度来看,使用 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-z、A-Z、0-9、_ 和-)
- URL 参数值不能包含
@(除非 URL 编码)
-
@@@ 不能出现在查询字符串中的任何位置
您只需按照您希望的顺序在脚本顶部定义 URL 参数名称。它们保存在环境变量VAR_NAME_01、VAR_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 中说...