【问题标题】:Rewriting dynamic URLs重写动态 URL
【发布时间】:2011-10-09 12:38:18
【问题描述】:

我正在尝试将 1 个动态 URL 重写为另一个动态 URL,如下所示;

/category?category=News to
/categorysearch/result/?q=news

我想知道是否有人知道如何在 htaccess 中完成此操作?

谢谢。

【问题讨论】:

    标签: apache .htaccess mod-rewrite


    【解决方案1】:

    所以最终的 EDITED 解决方案是(对于您链接的 .htaccess):

    RewriteCond %{REQUEST_FILENAME} ethical [NC]
    RewriteCond %{QUERY_STRING} (^|&|%26|%20)ethical(=|%3D)([^&]+) [NC]
    RewriteRule .* /catalogsearch/result/?q=%3 [L,R]
    

    如果我使用当前问题中的“类别”术语:

    RewriteCond %{REQUEST_FILENAME} category [NC]
    RewriteCond %{QUERY_STRING} (^|&|%26|%20)category(=|%3D)([^&]+) [NC]
    RewriteRule .* /categorysearch/result/?q=%3 [L,R]
    

    但是第一个比较清楚,类别这个词不是到处都用的。如果您想添加小写转换,我们甚至会这样做:

    # outside of a Directory section
    RewriteMap lowercase int:tolower
    # in a Directory section (not a .htaccess)
    RewriteCond %{REQUEST_FILENAME} category [NC]
    RewriteCond %{QUERY_STRING} (^|&|%26|%20)category(=|%3D)([^&]+) [NC]
    RewriteRule .* /catalogsearch/result/?q=${lowercase:%3} [L,R]
    

    但正如评论 最后一个 tolower 不能在 .htaccess 中工作 - 无论如何 .htaccess 很糟糕,真的,对于表演,你真的应该考虑设置 AllowOverride None 并移动所有这些虚拟主机中的东西。诸如 rewriteMaps 之类的好东西不能用于 .htaccess 文件。

    所以现在我将解释规则。首先,您遇到的主要问题是 "?" 之后的所有内容都是 query_string,而不是 请求的文件名。大多数 rewriteRules 尝试处理请求的文件名。所以我首先检查我们是否在目标请求的文件名上:

    RewriteCond %{REQUEST_FILENAME} category [NC]
    

    然后我们将处理查询字符串(问号之后的所有内容)。我们可以写一些更简单的东西:

    RewriteCond %{REQUEST_FILENAME} category [NC]
    RewriteCond %{QUERY_STRING} ^category=(.+) [NC]
    RewriteRule .* /catalogsearch/result/?q=${lowercase:%1} [L,R]
    

    在可用于 RewriteRule 的变量 %1 中捕获 ?category= 之后的所有内容。但是 QUERY_STRING 参数有几个问题,让我们尝试一下:

    • 尚未对该参数进行url解码
    • 类别可能不是参数列表中的第一个参数
    • 它甚至可能不是最后一个 (&foo=bar)
    • 前面可以留一些空格

    已编辑

    我的第一个答案是:

    RewriteCond %{REQUEST_FILENAME} category [NC]
    RewriteCond %{QUERY_STRING} [^|&|%26|%20][category](=|%3D)([^&]+) [NC]
    RewriteRule .* /catalogsearch/result/?q=${lowercase:%2} [L,R]
    

    [^|&|%26|%20] 发现它可能是起始参数或 & 或空格之后的参数,%26 是 & urlencoded。

    但这是错误,感谢@mootinator 评论,我已经检查了更多,[category] ​​匹配 'category' 但也匹配 'atcatcategory' 和这些字母的任何组合。

    RewriteCond %{QUERY_STRING} category(=|%3D)([^&]+) [NC]
    

    匹配 'category' 参数,删除 ^ 允许将此参数放置在任何位置。但这也将匹配名为subcategory 的参数。所以第一个字母必须是空格或&(或查询字符串的开头)。

    这就是 [^|&|%26|%20] 的原因,对我来说,这意味着链 OR & 或空格或 & 以 urlencoded 开头。但这也是错误^ 里面的[] 表示否定。所以我们也需要在这里使用匹配括号:(^|&|%26|%20),现在它可以工作了,唯一的问题是参数的值现在是 %3 而不是 %2

    然后我们捕获(类别)单词,实际上我们应该逐个字母地捕获它,大写、小写和大小写字母的 urlencoded 版本,就像一个糟糕的[c|C|%43|%63][a|A|%61|%41][t|T|%74|...]to be continued --我也许应该使用括号而不是括号,见鬼,检查urlencoded characters list here

    (=|%3D) 是否是 '=' 字符 urlencoded。 我本可以使用[=|%3D],但在这种情况下%3D 匹配得不是很好,我不明白为什么(mod_rewrite 是一片奇怪的地方)。由于使用了第一个匹配括号,我们将不得不使用 %2 变量而不是 %1。

    然后我们有很好的([^&]+),它表示任何东西,但不是“&”。

    在这些条件之后,我们应用 RewriteRule。我们把所有东西(这是.*)重定向到/catalogsearch/result/?q=%2,我们使用%3而不是$1$3,因为我们没有在rewriteRule上捕获任何东西,而是在之前的条件下(%3是在最后一个条件下捕获的第三个数据,所以它是([^&]+))。 如果您在 rewriteRule 中添加 QSA 标志 ([L,R,QSA]),您甚至可以在最终查询字符串中取回其他参数,以便:

    ethical?bar=toto& ethical=Foo&zorglub=titi 
    => is redirected to 
    catalogsearch/result/?q=foo&bar=toto&%2520ethical=Foo&zorglub=titi
    

    如果我玩一点 url 编码:

    ethical?bar=toto%26 ethical%3DFoo&zorglub=titi 
    => is redirected to 
    catalogsearch/result/?q=foo&bar=toto%2526%2520ethical%253DFoo&zorglub=titi
    

    但这还没有结束,我会让你处理所有你可能遇到的 urlencoding 问题,你想检测 Foo 值的所有变化并将它们与 tolower 混合(这里它被破坏了)。您甚至可能不会在参数或额外属性中遇到编码 url 的这些问题,但这很有趣 :-)

    【讨论】:

    • (=|%3D) 表示=%3D[=|%3D] 表示%|3D,所以不,你不能使用@987654 @ 因为它根本不匹配 %3D。 ([category] 显然不是你想的那样)
    • @mootinator:谢谢你,我重新设计了解决方案。
    • 非常感谢您的解决方案和详细的回答,非常感谢!
    • 好的,所以给我赏金:-)
    【解决方案2】:

    根据您要做什么以及需要做的具体事情,有两种选择。

    第一个是 Rob W 的解决方案,应该将用户从 /category?category=News 重定向到 /categorysearch/result/?q=News

    如果您的 URL 看起来是区分大小写的,您可能需要查看如下 PHP 脚本:

    $matches = array();
    if( preg_match( "/^/category\?category=(.+)/", $_SERVER['REQUEST_URI'], $matches ) ) {
        header( 'Location: http://' . $_SERVER['HTTP_HOST'] . '/categorysearch/result/?q= . strtolower($matches[1]) );
    }
    else {
        //ERROR HANDLING
    }
    

    一旦确定,您可以使用如下规则使用完全小写的参数进行重定向。

    RewriteRule ^category\?category=(.+)$ redirect.php [L]
    

    总之,这个解决方案会将/category?category=News重定向到/categorysearch/result/?q=news

    【讨论】:

    • +1 表示基于 PHP 的解决方案,而且 -1 表示在 RewriteRule 中测试查询字符串。它只是不那样工作。
    • @SáT - 它根本不起作用吗?我以前从未在 RewriteRule 中真正使用过查询字符串,只是假设它们会作为资源的一部分。
    • 来自docs:“模式不会与查询字符串匹配。相反,您必须使用带有 %{QUERY_STRING} 变量的 RewriteCond。但是,您可以在替换字符串,包含查询字符串部分。”所以是的,像 category\?cat=(.*) 这样的规则永远不会匹配任何东西,而且不会起作用。
    • 啊,好吧。根本不知道,因为我一直在使用它们来清理 URL,而不是任何这类事情。感谢您的信息!
    【解决方案3】:

    我认为

    RewriteRule ^/category?category=(.*) /categorysearch/result/?q=news

    会做的。

    【讨论】:

    • 不,不会。你不能像这样测试查询字符串,你需要一个 rewriteCond 。此外,这只会将每个请求重定向到 /categorysearch/result/?q=news 地址,这几乎是不可取的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2015-05-07
    • 2011-06-02
    • 2021-11-06
    • 2014-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多