【问题标题】:Can't use parentheses in RewriteCond QUERY_STRING不能在 RewriteCond QUERY_STRING 中使用括号
【发布时间】:2020-08-05 16:52:54
【问题描述】:

https://serverfault.com/questions/1013461/cant-use-parentheses-in-rewritecond-query-string 移出,因为它是这里的主题。


我需要从旧网址捕获 UID 并将其重定向到新格式。

example.com/?uid=123 应该重定向到example.com/user/123

应该怎么做:

RewriteCond %{QUERY_STRING} ^uid=(\d+)$
RewriteRule ^$ /user/%1? [L]

这根本不重定向。

但是,这样做:

RewriteCond %{QUERY_STRING} ^uid=\d+$
RewriteRule ^$ /user/%1? [L]

它转到example.com/user。 UID 被忽略,但它确实重定向。

注意:我所做的只是删除了第二个示例中的括号。

这是为什么?如何匹配查询并捕获 UID 的值?


更新

这是一个 laravel 应用。我发现我确实看到的重定向可能来自应用程序,而不是 Apache。

很快就会自动回答...

暂时添加 R=302 会得到想要的结果:

RewriteCond %{QUERY_STRING} ^uid=(\d+)$
RewriteRule ^$ /user/%1? [L,R=302]

当然,这会将 302 重定向发送到 /users/123。我想看看这是否可以通过内部重写来完成......

以下是 laravel 默认 .htaccess 中的一些规则:

# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

这会捕获不指向真实文件的路径,并将它们指向 laravel 应用程序。当它被删除时,Apache 会以 404 响应 /users/1234。

https://httpd.apache.org/docs/2.4/rewrite/flags.html#flag_l

这样的重写可以追溯到 Apache 的 URL 解析器。然后再次处理 .htaccess(因为它仍然适用于这个新 URL)。在这一点上,我希望上述规则能够拾取不存在的路径并将其指向 laravel 应用程序...

找到了。现在写一个答案。

【问题讨论】:

  • 新的一天,我想我刚刚找到了线索。等我弄明白了再贴出来。
  • (FWIW 你的问题可能被认为是网站管理员的更多主题。虽然它仍然是 ServerFault 的主题,......等等。)我实际上是在当您在 SF 上删除问题时的评论中间...
  • "...但它确实" - 肯定有其他事情发生。这里有一些奇怪之处......上面的指令不是“重定向”,而是“内部重写”。如果您看到“重定向”,那么似乎还有其他事情在这样做?
  • 但是从/?uid=123/user/123rewrite 没有多大意义——这应该是一个外部重定向(如果有的话)。否则,/user/123 如何被路由? (这可能是对/?uid=123 的内部重写?尽管严格来说这应该是直接重写处理请求的文件,例如/index.php?uid=123,而不是让 mod_dir 为目录索引发出额外的内部子请求。( ?))
  • 你说得对。我必须指定 R=302 来解决它。我正在看到的重定向来自应用程序。重要的缺失信息:这是一个 laravel 应用程序。我会尽快发布答案。 (抱歉删除,顺便说一句)

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


【解决方案1】:

答案

怀特先生是对的。您必须添加 R=302R=301 才能执行重定向。普通的重写是行不通的。

RewriteCond %{QUERY_STRING} ^uid=(\d+)$
RewriteRule ^$ /user/%1? [L,R=302]

原因

所以,Laravel 的工作方式是:

  • 您请求/some/file
  • .htaccess 告诉 apache,“嘿,apache,如果你请求一个不存在的文件,就假装它是给 index.php 的”
  • apache 说,“嘿 php,我有一个运行 index.php 的请求,而 url 是 /some/file
  • php 运行脚本 --whoah-- 是一个巨大的 laravel 应用程序
  • 不管怎样,“嘿 laravel,服务器说/some/file 是网址”
  • laravel 做了所有花哨的事情,它会尝试将 url 匹配到您的路由之一

现在,我添加了一条规则,将某个 URL 重写为 Laravel 应该处理的虚拟 URL。我正在匹配查询参数,但这无关紧要。 (详情见下文)

当 Apache 的重写模块遇到没有 [R] 标志的 RewriteRule 时,它​​会重写 URL 并将其发送回 URL 处理程序。然后,Apache 的 URL 处理程序会根据所有规则(包括任何适用的 .htaccess 文件中的规则)处理新 URL。

所以所有正确的规则确实都得到了应用。

以下是关键启示: 最初请求的 URL 从未改变。 因此,当 Apache 能够使用正确的文件将请求传递给 PHP 时,它也沿旧 URL 发送。

因此,我们必须告诉 Apache 发送 301 或 302 重定向响应,而不仅仅是重写请求。用户将使用 Laravel 解析路由所需的 URL 发送另一个请求。


但是有/没有括号的不同行为呢?

答案就在 Laravel 的默认 .htaccess 中。让我们看看我没有括号的旧规则:

RewriteCond %{QUERY_STRING} ^uid=\d+$
RewriteRule ^$ /user/%1? [L]

没有括号来获取uid值,%1为空。所以我们最终将 URL 重写为 /user/

现在,我们要看看另一组 Laravel 规则:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]

这会规范化 url,以便虚拟路径/路由不包含尾部斜杠。这样做会使路由解析更容易。

这会返回一个 301 重定向到 `/users'。这与我们用括号得到的 200 个非常不同,但这并不意味着括号的行为不同。正如怀特先生在 cmets 中所说的那样,肯定是其他人在做这件事。

我希望你喜欢这次旅程。我更希望这能将一些可怜、困惑的灵魂从数小时的折磨中解救出来。 :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-29
    • 2016-05-03
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 2012-06-27
    • 2015-05-21
    • 1970-01-01
    相关资源
    最近更新 更多