htaccess 中的 RewriteRule 失败,但它可能是我的主机 解决方案

问题描述

我读过 Self Sabotage is Not asking for help 所以我在这里

所以,我有一个网站...使用 WAMP 效果很好。它在我当前的主机上运行良好。但是我需要切换到新主机,现在它失败了。我认为这是一个 .htaccess 问题,但现在我不确定。在我当前的主机上,我没有 .htaccess 文件,而且效果很好。在我使用 WAMP 的 localhost 服务器上,我有与我的新主机相同的东西,但我只是禁用了 .htaccess 文件,将其重命名BAD.htaccess,并且该站点仍然运行良好。这就是为什么我认为这是一个服务器端问题,我需要一些帮助。在虚拟主机中的 WAMP 服务器上,我为该“域”禁用了 +FollowSymLinks。在我目前的主机上,我没有简单的方法可以做到这一点,所以他们给了我任何东西,但它有效。

我目前在 Ionos 工作,并已转向使用 cPanel 的 GreenGeeks。到目前为止,我还没有找到可编辑的 vhosts 文件删除 +FollowSymLinks,如果这甚至是问题所在。

也许它可以用 .htaccess 来完成,如果是这样,这就是我需要做的。首先是我当前的 .htaccess

Options +FollowSymLinks
RewriteEngine on
RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f

RewriteRule ^poems$ poems.PHP [R]
#RewriteRule ^poems/$ poems.PHP

RewriteRule ^collections$ collections/ [R]
RewriteRule ^collections/$ collections.PHP

RewriteRule ^poem$ poem/ [R]
RewriteRule ^poem/$ poem.PHP

RewriteRule ^poem/([0-9]+)/([a-zA-Z])$ poem.PHP?num=$1&poem=$2 [NC,L]

RewriteRule ^collection$ collection/ [R]
RewriteRule ^collection/$ collection.PHP

# RewriteRule ^poem/([0=9]+)$ indpoem.PHP?num=$1  [NC,L]

通过前两个设置,我可以转到 example.com/poems,它会重定向或重写到 example.com/poems.PHP,但仍然看起来像 example.com/poems。与 collections 相同。在新主机上,这些重写规则确实会重写它,但 URL 或 URI 显示 example.com/poems.PHP,根据当前的 SEO 标准,我不希望这样。不过,我可以忍受。

但是,当我进入下一个级别时... example.com/poem/#/poem-name 在我的新主机上失败了。我确实有一个名为 poem.PHP文件,它应该重写。在该文件中,我使用以下内容获取 #名称...

$URL = explode("/",$_SERVER['REQUEST_URI']);

所以我不必执行 _GET

如您所见,我尝试执行 RewriteRule 以将其从第一个更改为 example.com/poem?111&name,但这似乎很愚蠢,因为在 WAMP 上我无需执行任何操作。我可以尝试再次将其重写为相同的 URL,但我有一种行不通的感觉。如果是这样,它可能是 poem.PHP/#/name/

我在使用 cPanel 时遗漏了任何关于服务器配置的想法。我什至尝试过

Options -FollowSymLinks

在我的 .htaccess 文件中没有成功。

任何帮助将不胜感激。我的 WAMP 和新主机拥有所有最新版本的 Apache 和 PHP

解决方法

这里有几个问题...

  • 要使网站在没有完全没有 .htaccess 文件的情况下工作(在您的 WAMP 开发服务器和当前主机上),那么 MultiViews(mod_negotiation 的一部分)必须已启用。 MultiViews/foo 改写为 /foo.php

  • 如果 MultiViews 已启用,那么您当前的 .htaccess 文件实际上已被覆盖,因为 MultiViews 内容协商发生在您的 mod_rewrite 指令被处理之前,因此您的 RewriteRule 模式无法匹配。

  • MultiViews 在 Apache 上默认禁用,需要“显式”启用。不幸的是,一些共享主机确实在服务器配置中启用了此功能(这会导致比修复更多的问题 - 如果您没有预料到它。)

在新主机上,这些重写规则确实会重写它,但 URL 或 URI 显示 example.com/poems.php

RewriteRule ^poems$ poems.php [R]
  • 因为 MultiViews 被禁用并且您的指令从外部“重定向”/poems/poems.php。这里没有“重写”。 R (redirect) 标志触发外部重定向。
RewriteRule ^poem$ poem/ [R]
RewriteRule ^poem/$ poem.php
  • 但是,对于 /poem,您正在重定向到 /poem/(附加尾部斜杠),但您省略了 L 标志,因此处理继续并且请求被进一步重写为/poem.php。但是因为您已经触发了 Redirect,请求被“重定向”(而不是重写)到 /poem.php,再次暴露 .php

  • 重定向应该几乎总是包含 L 标志。事实上,您的所有规则都应包含用于优化和防止意外冲突的 L 标志。

  • 为什么要重定向以附加尾部斜杠(好像这是首选的规范 URL)?您在问题文本中没有提及这一点,据我所知,只有一个示例在 URL 上包含一个斜杠?那么,什么是首选/规范 URL?你链接到什么网址?顺便说一句,MultiViews 不会附加尾部斜杠 - 因此要么不需要此重定向,要么您的网站在没有 .htaccess 文件的 WAMP/当前主机上实际上“运行良好”。 (?)(就我个人而言,我不会使用尾部斜杠。)

 RewriteRule ^poem/([0-9]+)/([a-zA-Z])$ poem.php?num=$1&poem=$2 [NC,L]
 :
 $URL = explode("/",$_SERVER['REQUEST_URI']);
  • 您的 PHP 脚本解析请求的 URL 路径(即 $_SERVER['REQUEST_URI']),它没有引用查询字符串。但是,上面的 RewriteRule 指令正在重写查询字符串 - 这似乎是完全多余的(“愚蠢” - 正如您所建议的那样)。因为您没有在 PHP 脚本中使用查询字符串,所以在使用 MultiViews 时请求仍然“有效”。

  • 根据您的 PHP 脚本,您只需将请求重写为 poem.php,无需查询字符串。 (这就是 MultiViews 所做的。虽然,严格来说,MultiViews 将 /poem/123/name 重写为 /poem.php/123/name - 将额外的 URL-path 作为 path-info 传递给 poem.php。 )

  • 此正则表达式仅匹配第三个(名称)路径段中的单个字母,因此它将无法匹配 /poem/123/name 形式的请求 URL,因此请求不会重写为 {{1}并且请求失败(我怀疑是 404)。

  • 这个正则表达式也不匹配尾部斜杠。 (那么,尾部斜杠真的规范吗?)

poem.php
  • 这些条件在您放置它们的地方完全是多余的。 RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f 指令仅适用于后面的第一个 RewriteCond 指令。
RewriteRule
  • 您需要 Options -FollowSymLinks 才能使 mod_rewrite 工作。不要尝试禁用此功能。 FollowSymLinks 实际上是 默认 Apache 设置,因此您只需要在 FollowSymLinks 中显式启用它(即 +FollowSymLinks),如果它已在服务器中禁用配置。

解决方案

就个人而言,我不会在规范 URL 上使用尾部斜杠。 (这与您的大多数示例和规则中使用的正则表达式一致。)

因此,将以上几点结合起来:

.htaccess

另一方面,如果规范 URL 应包含尾部斜杠,则相应地更改它:

Options +FollowSymLinks -MultiViews

RewriteEngine on

# Canonical redirect to remove trailing slash (from non-directories)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)/$ /$1 [R,L]

# Internal rewrites to ".php"
RewriteRule ^poems$ poems.php [L]
RewriteRule ^collections$ collections.php [L]
RewriteRule ^poem(/\d+/[\w-]+)?$ poem.php [L]
RewriteRule ^collection$ collection.php [L]

如果您有许多这样的 URL/页面,那么您可以将其设置为完全“通用”,而无需明确命名每个 URL/文件。 IE。 “诗”、“集”等


或者,您只需启用 MultiViews 并让 mod_negotiation 重写 URL。但是,您将无法在重写之前规范化尾部斜杠或验证请求,并且 MultiViews 适用于所有内容,而不仅仅是您的 Options +FollowSymLinks -MultiViews RewriteEngine on # Canonical redirect to append trailing slash to "all" URLs RewriteRule !/$ ${REQUEST_URI}/ [R,L] # Internal rewrites to ".php" RewriteRule ^poems/$ poems.php [L] RewriteRule ^collections/$ collections.php [L] RewriteRule ^poem/(\d+/[\w-]+/)?$ poem.php [L] RewriteRule ^collection/$ collection.php [L] 文件,因此可能会创建重复的内容。如果您需要进行任何特定的重写,例如重写查询字符串,则 MultiViews 可能会发生冲突。

.php