提问人:TerryE 提问时间:2/6/2012 最后编辑:CommunityTerryE 更新时间:12/2/2022 访问量:141335
调试 .htaccess 重写规则的提示
Tips for debugging .htaccess rewrite rules
问:
许多发帖者在其 .htaccess
文件中调试其 RewriteRule 和 RewriteCond 语句时遇到问题。其中大多数都使用共享托管服务,因此无权访问根服务器配置。他们无法避免使用文件进行重写,也无法启用 RewriteLogLevel“,正如许多受访者所建议的那样。此外,还有许多特定的陷阱和约束没有得到很好的涵盖。对于大多数人来说,设置本地测试LAMP堆栈涉及太多的学习曲线。.htaccess
.htaccess
所以我的问题是,我们如何建议他们自己调试他们的规则。我在下面提供一些建议。如能提出其他建议,将不胜感激。
了解 mod_rewrite 引擎循环处理
.htaccess
文件。引擎运行以下循环:do execute server and vhost rewrites (in the Apache Virtual Host Config) find the lowest "Per Dir" .htaccess file on the file path with rewrites enabled if found(.htaccess) execute .htaccess rewrites (in the user's directory) while rewrite occurred
因此,您的规则将被重复执行,如果您更改 URI 路径,那么它最终可能会执行其他文件(如果存在)。因此,请确保在必要时通过添加额外的内容来终止此循环以停止规则触发。此外,删除任何较低级别的重写规则集,除非明确打算使用多级规则集。
.htaccess
RewriteCond
.htaccess
通过针对一组测试模式进行测试,确保每个正则表达式的语法正确无误,以确保该语法是有效的,并且对各种测试 URI 执行预期操作。有关更多详细信息,请参阅下面的答案。
在测试目录中以增量方式构建规则。您可以利用“在路径上执行最深的文件”功能来设置单独的测试目录(树)并在此处调试规则集,而不会搞砸您的主要规则并停止您的站点工作。您必须一次添加一个,因为这是将故障本地化为单个规则的唯一方法。
.htaccess
使用虚拟脚本存根转储服务器和环境变量。(见清单 2)例如,如果您的应用程序使用,那么您可以将其复制到子目录中并使用它来测试您的博客规则。您还可以使用环境变量来确保重写引擎正确解释替换字符串,例如
blog/index.php
test/blog/index.php
test
RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html]
并在 phpinfo 转储中查找这些 REDIRECT_* 变量。顺便说一句,我使用了这个,并在我的网站上发现我不得不使用。在重定向器循环的情况下,REDIRECT_REDIRECT_* 变量列出上一遍。 等等。
%{ENV:DOCUMENT_ROOT_REAL}
确保您不会被浏览器缓存不正确的 301 重定向所困扰。请参阅下面的答案。我感谢乌尔里希·帕尔哈(Ulrich Palha)。
重写引擎似乎对上下文中的级联规则很敏感(即 a 导致替换的地方,这属于其他规则),因为我发现了内部子请求 (1) 的错误,以及不正确的PATH_INFO处理,这通常可以通过使用 [NS]、[L] 和 [PT] 标志来防止。
.htaccess
RewriteRule
还有什么意见或建议吗?
清单 1 -- phpinfo
<?php phpinfo(INFO_ENVIRONMENT|INFO_VARIABLES);
答:
以下是有关测试规则的一些其他提示,这些提示可能会简化共享主机上用户的调试
1. 使用假用户代理
测试新规则时,请添加一个条件,以仅使用将用于请求的用户代理执行该规则。这样,它就不会影响您网站上的任何其他人。fake
例如
#protect with a fake user agent
RewriteCond %{HTTP_USER_AGENT} ^my-fake-user-agent$
#Here is the actual rule I am testing
RewriteCond %{HTTP_HOST} !^www\.domain\.com$ [NC]
RewriteRule ^ http://www.domain.com%{REQUEST_URI} [L,R=302]
如果您使用的是 Firefox,则可以使用 User Agent Switcher 创建虚假的用户代理字符串并进行测试。
2. 在完成测试之前不要使用 301
我看到很多帖子,人们仍在测试他们的规则,他们正在使用 301。不要。
如果您没有在您的网站上使用建议 1,那么不仅您,而且当时访问您网站的任何人都会受到 301 的影响。
请记住,它们是永久性的,并且由您的浏览器主动缓存。 改用 302,直到您确定为止,然后将其更改为 301。
3. 请记住,301 会积极缓存在您的浏览器中
如果您的规则不起作用,并且您看起来正确,并且您没有使用建议 1 和 2,请在清除浏览器缓存后或在隐私浏览时重新测试。
4. 使用 HTTP 捕获工具
使用 HTTP 捕获工具(如 Fiddler)查看浏览器和服务器之间的实际 HTTP 流量。
虽然其他人可能会说你的,但你可以反而看到并报告,迅速缩小问题范围。site does not look right
all of the images, css and js are returning 404 errors
当其他人会报告你时,你将能够看到他们从 开始。即使 URL C 是最终目标,您也会知道这对 SEO 不利,需要修复。started at URL A and ended at URL C
URL A, were 302 redirected to URL B and 301 redirected to URL C
您将能够看到在服务器端设置的缓存标头,重放请求,修改请求标头以进行测试......
评论
[L,R=302]
[L, R=302]
[L,R]
302
确保每个正则表达式的语法正确
通过针对一组测试模式进行测试,以确保该语法是有效的语法,并使用各种测试 URI 执行预期操作。
请参阅下面的 regexpCheck.php 以获取一个简单的脚本,您可以将其添加到站点中的私有/测试目录以帮助您执行此操作。我一直保持简短而不是漂亮。只需将其传递到测试目录中的文件中即可在您的网站上使用它。这将帮助您构建任何正则表达式,并在执行此操作时根据测试用例列表对其进行测试。我在这里使用的是PHP PCRE引擎,但是在查看了Apache源代码后,这与Apache中使用的引擎基本相同。有许多 HowTos 和教程提供了模板,可以帮助您培养正则表达式技能。regexpCheck.php
清单 1 -- regexpCheck.php
<html><head><title>Regexp checker</title></head><body>
<?php
$a_pattern= isset($_POST['pattern']) ? $_POST['pattern'] : "";
$a_ntests = isset($_POST['ntests']) ? $_POST['ntests'] : 1;
$a_test = isset($_POST['test']) ? $_POST['test'] : array();
$res = array(); $maxM=-1;
foreach($a_test as $t ){
$rtn = @preg_match('#'.$a_pattern.'#',$t,$m);
if($rtn == 1){
$maxM=max($maxM,count($m));
$res[]=array_merge( array('matched'), $m );
} else {
$res[]=array(($rtn === FALSE ? 'invalid' : 'non-matched'));
}
}
?> <p> </p>
<form method="post" action="<?php echo $_SERVER['SCRIPT_NAME'];?>">
<label for="pl">Regexp Pattern: </label>
<input id="p" name="pattern" size="50" value="<?php echo htmlentities($a_pattern,ENT_QUOTES,"UTF-8");;?>" />
<label for="n"> Number of test vectors: </label>
<input id="n" name="ntests" size="3" value="<?php echo $a_ntests;?>"/>
<input type="submit" name="go" value="OK"/><hr/><p> </p>
<table><thead><tr><td><b>Test Vector</b></td><td> <b>Result</b></td>
<?php
for ( $i=0; $i<$maxM; $i++ ) echo "<td> <b>\$$i</b></td>";
echo "</tr><tbody>\n";
for( $i=0; $i<$a_ntests; $i++ ){
echo '<tr><td> <input name="test[]" value="',
htmlentities($a_test[$i], ENT_QUOTES,"UTF-8"),'" /></td>';
foreach ($res[$i] as $v) { echo '<td> ',htmlentities($v, ENT_QUOTES,"UTF-8"),' </td>';}
echo "</tr>\n";
}
?> </table></form></body></html>
评论
import_request_variables
extract($_GET)
extract($_POST)
我在尝试调试我的mod_rewrite问题时发现了这个问题,它肯定有一些有用的建议。但归根结底,最重要的是确保你的正则表达式语法正确无误。由于我自己的 RE 语法存在问题,安装 regexpCheck.php 脚本不是一个可行的选择。
但是,由于Apache使用Perl兼容的正则表达式(PCRE),因此任何有助于编写PCRE的工具都应该有所帮助。我过去曾将 RegexPlanet 的工具用于 Java 和 Javascript RE,很高兴发现它们也支持 Perl。
只需输入您的正则表达式和一个或多个示例 URL,它就会告诉您正则表达式是否匹配(“~=”列中的“1”),如果适用,任何匹配的组(“拆分”列中的数字将对应于 Apache 期望的数字,例如 $1、$2 等)。他们声称 PCRE 支持处于“测试阶段”,但这正是我解决语法问题所需要的。
http://www.regexplanet.com/advanced/perl/index.html
我只是简单地在现有答案中添加评论,但我的声誉还没有达到那个水平。希望这对某人有所帮助。
评论
确保在变量前面使用百分号,而不是美元符号。
它是 ,不是 。error_log中不会有任何内容,不会有内部服务器错误,您的正则表达式仍然正确,规则将不匹配。如果你经常使用 django / genshi 模板并在肌肉记忆中进行变量替换,这真的很可怕。%{HTTP_HOST}
${HTTP_HOST}
${}
评论
我浪费了几个小时中的一个:
如果您已经应用了所有这些提示,并且由于您无权访问服务器错误日志而只出现 500 个错误,那么问题可能不在于 .htaccess,而在于它重定向到的文件。
在我修复了我的 .htaccess 问题后,我又花了两个小时试图再修复它,即使我只是忘记了一些权限。
评论
.htaccess
关于4.,在完成所有重写后,您仍然需要确保您的“虚拟脚本存根”实际上是目标URL,否则您将看不到任何内容!
一个类似/相关的技巧(请参阅此问题)是插入一个临时规则,例如:
RewriteRule (.*) /show.php?url=$1 [END]
其中有一些非常简单的脚本,只显示其参数(如果需要,您也可以显示环境变量)。show.php
$_GET
这将在将重写插入规则集时停止重写,就像调试器中的断点一样。
如果您使用的是 Apache <2.3.9,则需要使用 而不是 ,然后可能需要添加:[L]
[END]
RewriteRule ^show.php$ - [L]
在规则集的最顶部,如果 URL 本身正在被重写。/show.php
不要忘记,在 .htaccess 文件中,它是匹配的相对 URL。
在 .htaccess 文件中,以下 RewriteRule 永远不会匹配:
RewriteRule ^/(.*) /something/$s
评论
/
(类似于 Doin 的想法) 为了显示正在匹配的内容,我使用以下代码
$keys = array_keys($_GET);
foreach($keys as $i=>$key){
echo "$i => $key <br>";
}
将其保存到服务器根目录上的 r.php 中,然后在 .htaccess
中进行一些测试 例如,我想匹配不以语言前缀开头的网址
RewriteRule ^(?!(en|de)/)(.*)$ /r.php?$1&$2 [L] #$1&$2&...
RewriteRule ^(.*)$ /r.php?nomatch [L] #report nomatch and exit
评论
QUERY_STRING
在线.htaccess重写测试
我发现这个谷歌搜索正则表达式帮助,它为我节省了大量时间,让我不必在每次进行小修改时上传新文件。.htaccess
从网站:
HTSaccess测试仪
要测试您的htaccess重写规则,只需填写您应用规则的URL,将htaccess的内容放在较大的输入区域,然后按“立即检查”按钮。
评论
设置环境变量并使用标头来接收它们:
您可以使用 RewriteRule 行创建新的环境变量,如 OP 所述:
RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html]
但是,如果你不能让服务器端脚本工作,那么你怎么能读取这个环境变量呢?一种解决方案是设置标头:
Header set TEST_FOOBAR "%{REDIRECT_TEST0}e"
该值接受格式说明符,包括环境变量的说明符(不要忘记小写 e)。有时,您需要添加前缀,但我还没有弄清楚何时添加前缀以及何时不添加前缀。%{NAME}e
REDIRECT_
评论
REDIRECT_
我会把这个留在这里,也许是显而易见的细节,但让我头疼了几个小时:
请谨慎使用,因为 @Krist van Besien 在他的回答中所说的是完全正确的,但不适用于REQUEST_URI字符串,因为此 TestString 的输出以 .所以要小心:%{REQUEST_URI}
/
RewriteCond %{REQUEST_URI} ^/assets/$
^
| check this pesky fella right here if missing
如果您打算在 .htacesss 中编写不止一行规则,
甚至不要考虑尝试其中一种热修复方法来调试它。
我浪费了几天时间来制定多个规则,却没有得到 LOG 的反馈,但最终还是放弃了。
我把Apache放在我的PC上,把整个网站复制到它的HDD上,然后用日志把整个规则集整理出来,非常快。
然后我回顾了我的旧规则,这些规则一直有效。我看到他们并没有真正做想要做的事情。一颗定时炸弹,地址略有不同。
重写规则中有很多坑,这根本不是一个直接的逻辑问题。
您可以在十分钟内启动并运行Apache,它是10MB,良好的许可证,*NIX/WIN/MAC,即使没有安装。
此外,检查服务器的标题行,并从其存档中获取相同版本的 Apache(如果它是旧的)。我的 OP 还在 2.0 上;许多事情都不受支持。
评论
mod_rewrite
htaccess
.htaccess
.htaccess
如果要创建重定向,请使用 curl 进行测试以避免浏览器缓存问题。 使用 -I 仅获取 http 标头。 使用 -L 跟踪所有重定向。
我观察到的一些错误发生在写作时.htaccess
在多个规则中重复使用 ,使用会导致其他规则在大多数情况下无能为力,因为它在单次点击中匹配所有 URL。^(.*)$
^(.*)$
因此,如果我们对此 url 使用规则,它也会消耗此 url 。sapmle/url
sapmle/url/string
应使用 [L]
标志来确保我们的规则已完成处理。
应该知道:
%n 和 $n 的差异
%n
在零件期间匹配,在零件上匹配。%{RewriteCond}
$n
%{RewriteRule}
RewriteBase 的工作原理
RewriteBase 指令指定要用于的 URL 前缀 per-directory (htaccess) RewriteRule 指令,用于替换 相对路径。
当您在 在每个目录 (HTSaccess) 上下文中替换,除非任何 满足以下条件:
原始请求和替换位于 DocumentRoot(而不是通过其他方式(如别名)访问)。 包含 RewriteRule 的目录的文件系统路径, 以相对替换为后缀的 URL 路径也可作为 服务器(这种情况很少见)。在 Apache HTTP Server 2.4.16 及更高版本中, 当通过 Alias 或 mod_userdir。
正如 @JCastell 所指出的,在线测试器在针对 .htaccess 文件测试单个重定向方面做得很好。然而,更有趣的是公开的 api,它可用于使用 json 对象批量测试 url 列表。但是,为了使其更有用,我编写了一个小型 bash 脚本文件,它利用 curl 和 jq 提交 url 列表并将 json 响应解析为 CSV 格式的输出,其中行号和规则在 htaccess 文件中匹配以及重定向的 url,这使得比较电子表格中的 url 列表并快速确定哪些规则不起作用非常方便。
如果您正在使用 url,您可能需要检查是否“启用 Mod 重写”
如果您不是在标准共享托管环境中工作,而是在您具有管理访问权限的环境(可能是您的本地测试环境)中工作,请确保使用 和 已启用。它们在默认的 Apache 安装中被禁用。在这种情况下,即使正则表达式完全有效,文件中配置的任何操作也不起作用。.htaccess
mod_rewrite
.htaccess
要启用以下功能,请执行以下操作:.htaccess
查找文件,在 Debian/Ubuntu 上,这在 中,在文件中的部分apache2.conf
/etc/apache2
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
并将该行更改为 。AllowOverride None
AllowOverride All
要启用模块:mod_rewrite
在 Debian/Ubuntu 上,执行
sudo a2enmod rewrite
顺便说一句,要禁用模块,您可以使用 .a2dismode
a2enmode
完成上述配置更改后,重启 Apache 以使其生效:
sudo systemctl restart apache2
调试它的最佳方法!
添加到 apache 以记录 的所有通知。如果您在共享主机上并且无权访问,请在本地测试它并上传到实时站点。一旦启用,它会在很短的时间内生成一个非常大的日志,这意味着它无论如何都无法在实时服务器上进行测试。LogLevel notice rewrite:trace8
httpd.conf
mod_rewrite
httpd.conf
评论
也许调试重写规则的最佳方法根本不使用重写规则,而是将 URL 处理从 htaccess 文件推迟到 PHP 文件(我们称之为 router.php)。然后,您可以使用PHP进行任何您喜欢的操作,并具有适当的错误检测和通常的调试方法。这甚至运行得更快,因为您不必使用重写模块。
要立即将控制权从 .htaccess 转移到 router.php,用于文件系统中找不到的任何 URL,只需在 .htaccess 中输入以下行:
FallbackResource router.php
是的,真的就是这么简单。是的,它确实有效。试一试。
注意:您可能需要在 .htacess 文件中使用 ErrorDocument 指令,以便将某些 URL 的控制权显式转移到 HTTP 状态为 404 的路由器.php文件,尤其是在您从处理状态 404 的父 htaccess 文件继承时。这样一来,总共有两行将控制权转移到路由器文件。
评论