清除 php 文件的 url 时 htaccess 文件出错

Error in htaccess file when clean url of php file

当我打开我网站的这个页面时,出现 500 错误:

single-portfolio/3/bizdb-business-directory-data-scraping-uk-

我的 .htaccess 文件:

RewriteEngine on
RewriteCond %{THE_REQUEST} /([^.]+)\.php [NC]
RewriteRule ^ /%1 [NC,L,R]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [NC,L]
RewriteRule ^single-portfolio/([0-9]+)/([0-9a-zA-Z_-]+)$ single-portfolio.php?id=&title= [NC,L]

浏览器中显示的错误是:

Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request. Please contact the server administrator at postmaster@localhost to inform them of the time this error occurred, and the actions you performed just before this error. More information about this error may be available in the server error log.

错误日志报告:

Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace

就我个人而言,我认为最好在您的重写规则之间留一个空行并添加注释来解释每个规则的作用。

步骤 1:如果我理解第一个重写规则是将 /something.php 重定向到 /something:

RewriteCond %{THE_REQUEST} /([^.]+)\.php [NC]
RewriteRule ^ /%1 [NC,L,R]

由于 R 标志,这将强制浏览器返回并访问 /something

第 2 步:第二个重写规则:

RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [NC,L]

如果 PHP 文件存在,它是一个内部重定向服务,因此通常 /something 将在 /something.php 内部服务(如果存在)。 L 标志告诉 Apache 在这里停止并且不执行下一个重写规则。但是,问题是我们都认为 Apache 现在会停止,但事实并非如此! Apache 将获取结果 URL 并通过所有重写规则再次传递它,直到 URL 不再更改。这就是他们所说的“一轮”。因此,发生的事情是您返回到第一个将触发重定向的重写规则,这会造成您的“多次重定向”错误。

要停止这种情况,在最新版本的 Apache 中,您可以 use the END flag 而不是 L 标志:

RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [NC,END]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [NC,L]

这条规则(通过内部重写附加 .php 扩展名)是不正确的。

当请求 /single-portfolio/<anything> 时,这会导致 rewrite-loop,因为 /single-portfolio.php 存在(满足 条件 ),但此规则将错误地重写请求 /single-portfolio/<anything>.php,这通常会导致错误的 404(因为您期望最后一条规则捕获此请求),但由于 L 标志,重写引擎重新开始并重复重写请求到 /single-portfolio/<anything>.php.php/single-portfolio/<anything>.php.php.php 等等,直到服务器“中断”并返回 500 响应。

my answer to the following question on ServerFault with a more detailed explanation of this behaviour: https://serverfault.com/questions/989333/using-apache-rewrite-rules-in-htaccess-to-remove-html-causing-a-500-error

简单地将 L 更改为 END 将修复 rewrite-loop,但不会解决整体问题,因为您只会得到上面提到的错误 404(请求不会被正确重写)。

更改指令的顺序,使重写 ^single-portfolio/ 的最后一条规则位于附加 .php 扩展名的第二条规则之前(通过内部重写)将解决您眼前的问题,但是,您需要修复上述规则,以便测试您最终要重写的同一文件(否则,/php-file-that-exists/<anything> 形式的任何 URL 都会导致 rewrite-loop / 500 内部服务器错误响应,而不是预期的 404)。

例如:

RewriteEngine on

RewriteCond %{THE_REQUEST} /([^.]+)\.php [NC]
RewriteRule ^ /%1 [L,R]

RewriteRule ^single-portfolio/(\d+)/([\w-]+)$ single-portfolio.php?id=&title= [NC,L]

RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule ^ %{REQUEST_URI}.php [L]

注意:shorthand 字符 class \w[0-9a-zA-Z_]. And \dis the same as[0-9]` 相同。

第一条和最后一条规则上的 NC 标志完全是多余的。我会谨慎使用 ^single-portfolio/ 重写上的 NC 标志(这不是必需的),因为这可能会启用重复内容(例如 /single-portfolio/.../SiNgLe-PoRtFoLiO/...都有效并解析为相同的资源。)

一旦确认一切正常,通过外部重定向删除 .php 扩展的第一条规则最终应该是 301(永久)重定向。