apache - $_GET["foo"] 来自 RewriteRule 的 NULL
问题描述
我正在尝试将http://localhost/tour/hello重定向到http://localhost/tour.php?name=hello
我在我的 .htaccess 中尝试了以下内容
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/tour/(.+)/?$
RewriteRule ^tour/(.+)/?$ tour.php?name=$1 [L,QSA, NC]
它重定向到http://localhost/tour.php但 $_GET["name"] 始终为 NULL
如果我将目标页面更改为 tour.php 以外的任何内容,它就可以工作
RewriteRule ^tour/(.+)/?$ handler.php?name=$1
RewriteRule ^tour/(.+)/?$ blah.php?name=$1
所有工作
解决方案
您需要通过以下方式禁用内容协商:
Options -MultiViews
在您的 .htaccess 中。
和AcceptPathInfo off
。
一些解释:
第一个问题是内容协商。假设您有两个名为 tour.txt 和 tour.php 的文件,如果启用了内容协商,如果您的 URL 只是http://localhost/tour,没有扩展名,Apache 正在寻找具有任何扩展名并基于客户端的名为 tour 的文件首选项(特别是本示例的 Accept HTTP 标头),将尝试在 tour.txt 和 tour.php 之间找到最佳匹配以提供给客户端。
您的问题的第二个元素是 AcceptPathInfo:启用后,Apache 接受 URL 路径末尾的多余部分以将其填充为内部变量(例如 PHP 中众所周知$_SERVER['PATH_INFO']
的)。为了说明,假设您有一个文件 tour.php。因此,使用AcceptPathInfo on
, http://localhost/tour.php/extra/path调用 tour.php 并使用$_SERVER['PATH_INFO']
= /extra/path 而不是像通常预期的那样被视为不存在 (404) /with AcceptPathInfo off
。
现在,将 AcceptPathInfo 和内容协商结合起来:问题是您的规则尝试“拦截”以 tour/ 开头的内容,但 tour.php 存在 [是一个文件],因此它与您自己的规则冲突,因为路径 tour/foo [对于 URL http://localhost/tour/foo]首先由内容协商解析为 tour.php/foo 和“接受”为 tour.php 和$_SERVER['PATH_INFO']
= /foo 感谢 AcceptPathInfo。结论:在这种非常具体的情况下,没有发生重写,但看起来如此,因为内容协商 + AcceptPathinfo 通过登陆 tour.php 具有相同的效果,这就是为什么您没有得到您期望的查询字符串(名称=富)。
另请注意,规则中的 NC 标志之前不应有任何空格。
推荐阅读
- php - 如何在自定义命令中设置 cookie 并在中间件 Laravel 中获取
- node.js - Socket.io 消息/评论发送两次。如何解决这个问题?
- sql-server - 数据库/数据仓库设计建议
- c# - 使用 Triflejs 进行 Selenium 无头浏览器测试
- javascript - Svelte / Sapper - 无法从不同路线的 api 响应中保存数据
- rasa-nlu - 如何将 Rasa Chatbot 集成到网站中?
- javascript - 循环遍历数组内部时如何获取数组的名称?
- typescript - 遍历具有接口的对象,类型不兼容
- django - django-bootstrap4 和 bootstrap4 有什么区别?
- javascript - 在 JS 中导出 AES-KW 密钥