调试.htaccess重写规则的提示

Ter*_*ryE 264 apache .htaccess mod-rewrite

许多海报在调试文件中的RewriteRule和RewriteCond语句时遇到问题.htaccess.其中大多数使用共享托管服务,因此无权访问根服务器配置.他们无法避免使用.htaccess文件进行重写,并且无法像许多受访者所建议的那样启用RewriteLogLevel.还有许多.htaccess特定的陷阱和约束都没有得到很好的解决.设置本地测试LAMP堆栈对于大多数人来说需要太多的学习曲线.

所以在这里我的Q是我们怎么会建议他们调试他们的规则本身.我在下面提供一些建议.其他建议将不胜感激.

  1. 了解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
    
    Run Code Online (Sandbox Code Playgroud)

    因此,您的规则将重复执行,如果您更改URI路径,那么它可能最终会执行其他.htaccess文件(如果存在).因此,请确保终止此循环,必要时添加额外的内容RewriteCond以停止规则触发..htaccess除非明确意图使用多级规则集,否则还要删除任何较低级别的重写规则集.

  2. 通过针对一组测试模式进行测试,确保每个Regexp的语法都是正确的,以确保它是一个有效的语法,并完成您对各种测试URI的意图.请参阅下面答案了解更多详情

  3. 在测试目录中逐步构建规则. 您可以使用" .htaccess在路径功能上执行最深的文件"来设置单独的测试目录(树)和调试规则集,而无需搞砸主要规则并停止站点工作.您必须一次添加一个,因为这是将故障本地化为单个规则的唯一方法.

  4. 使用虚拟脚本存根转储服务器和环境变量.(参见清单2)如果您的应用程序使用了,blog/index.php那么您可以将其复制test/blog/index.php并使用它来测试test子目录中的博客规则.您还可以使用环境变量来确保重写引擎正确解释替换字符串,例如

    RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html]
    
    Run Code Online (Sandbox Code Playgroud)

    并在phpinfo转储中查找这些REDIRECT_*变量.顺便说一句,我使用过这个并在我的网站上发现我不得不使用它%{ENV:DOCUMENT_ROOT_REAL}.在重定向器循环的情况下, REDIRECT_REDIRECT_*变量列出前一个传递.等等..

  5. 确保您的浏览器不会因为错误的301重定向而被咬住.见下面的答案.我要感谢Ulrich Palha.

  6. 重写引擎似乎对.htaccess上下文中的级联规则很敏感(这是RewriteRule导致替换的地方,而这会导致进一步的规则),因为我发现了内部子请求(1)的错误,以及错误的PATH_INFO处理通过使用[NS],[L]和[PT]标志来防止.

还有其他意见或建议吗?

清单1 - phpinfo

<?php phpinfo(INFO_ENVIRONMENT|INFO_VARIABLES);
Run Code Online (Sandbox Code Playgroud)

Ulr*_*lha 127

以下是有关测试规则的一些其他提示,可以简化共享主机上的用户调试

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] 
Run Code Online (Sandbox Code Playgroud)

如果您使用的是Firefox,则可以使用用户代理切换器创建虚假用户代理字符串并进行测试.

2.在完成测试之前,请勿使用301

我看过很多帖子,人们仍在测试他们的规则,他们正在使用301.不要.

如果您未在自己的网站上使用建议1,不仅是您,而且当时访问您网站的任何人都会受到301的影响.

请记住,它们是永久性的,并且会被您的浏览器主动缓存.使用302而不是你确定,然后将其更改为301.

3.请记住,301是在您的浏览器中积极缓存的

如果您的规则不起作用并且它看起来正确,并且您没有使用建议1和2,则在清除浏览器缓存或隐私浏览后重新测试.

4.使用HTTP Capture工具

使用像Fiddler这样的HTTP捕获工具来查看浏览器和服务器之间的实际HTTP流量.

虽然其他人可能会说你的site does not look right,你可以看到并报告all of the images, css and js are returning 404 errors,快速缩小问题.

虽然其他人会报告你started at URL A and ended at URL C,你将能够看到他们开始URL A, were 302 redirected to URL B and 301 redirected to URL C.即使URL C是最终目标,您也会知道这对SEO有害,需要修复.

您将能够看到在服务器端设置的缓存标头,重放请求,修改请求标头以进行测试....


  • 乌尔里希,非常感谢这一投入.你已经把我想到的一些方面放在了我的清单中.在301调试问题上,我在"私人浏览"(AKA"色情模式")中使用Chrome,因为当您关闭窗口时会转储此状态信息.我希望你不要介意我不要"接受"这个重要的观点,而不是一个单一的最佳答案.再次感谢.:) (9认同)
  • 你不需要明确指定`[L,R = 302]`只做`[L,R]``默认是`302` (6认同)
  • @goodeye,同时查看"Chrome>设置>常规>在DevTools打开时禁用缓存"复选框. (2认同)

JCa*_*ell 77

在线.htaccess重写测试

我在RegEx帮助中找到了这个谷歌搜索,.htaccess每次我做一个小的修改时,它为我上传新文件节省了很多时间.

来自网站:

htaccess测试仪

要测试您的htaccess重写规则,只需填写您正在应用规则的网址,将htaccess的内容放在较大的输入区域,然后按"立即检查"按钮.

  • 感谢指向此工具的指针,我找到了调试问题的最直接方法. (5认同)
  • 首先看起来不错。但它错过了很多功能。不幸的是这不是一个可靠的工具。 (2认同)

Kri*_*ien 12

不要忘记.htaccess文件中它是匹配的相对URL.

在.htaccess文件中,以下RewriteRule永远不会匹配:

RewriteRule ^/(.*)     /something/$s
Run Code Online (Sandbox Code Playgroud)

  • 是的,输入Rewrite**规则**的字符串是相对的,因此在任何前导`/`上都被剥离,但是对于在Rewrite**Cond**命令中汇编的匹配字符串不会发生这种剥离. (4认同)

Ter*_*ryE 8

确保每个Regexp的语法都正确

通过测试一组测试模式来确保它是一个有效的语法,并完成你想要的全部测试URI.

请参阅下面的regexpCheck.php以获取一个简单的脚本,您可以将其添加到站点中的私有/测试目录以帮助您执行此操作.我保持这个简短而不是漂亮.只需将其放入regexpCheck.php测试目录中的文件即可在您的网站上使用它.这将帮助您构建任何正则表达式,并在执行此操作时针对测试用例列表对其进行测试.我在这里使用PHP PCRE引擎,但看过Apache源代码,这基本上与Apache中使用的相同.有许多HowTos和教程提供模板,可以帮助您建立正则表达式技能.

清单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>&nbsp; </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">&nbsp; &nbsp; 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>&nbsp;</p>
    <table><thead><tr><td><b>Test Vector</b></td><td>&nbsp; &nbsp; <b>Result</b></td>
<?php 
    for ( $i=0; $i<$maxM; $i++ ) echo "<td>&nbsp; &nbsp; <b>\$$i</b></td>";
    echo "</tr><tbody>\n";
    for( $i=0; $i<$a_ntests; $i++ ){
        echo '<tr><td>&nbsp;<input name="test[]" value="', 
            htmlentities($a_test[$i], ENT_QUOTES,"UTF-8"),'" /></td>';
        foreach ($res[$i] as $v) { echo '<td>&nbsp; &nbsp; ',htmlentities($v, ENT_QUOTES,"UTF-8"),'&nbsp; &nbsp; </td>';}
        echo "</tr>\n";
    }
?> </table></form></body></html>
Run Code Online (Sandbox Code Playgroud)


Sim*_*mon 6

确保使用变量前面的百分号,而不是美元符号.

%{HTTP_HOST},不是 ${HTTP_HOST}.error_log中没有任何内容,没有内部服务器错误,你的正则表达式仍然正确,规则将不匹配.如果你经常使用django/genshi模板并且${}在肌肉记忆中进行变量替换,这真的很可怕.


Rub*_*ben 6

我浪费了几个小时的一个:

如果您已经应用了所有这些提示并且由于您无法访问服务器错误日志而仅发生500个错误,则问题可能不在.htaccess中,而是在重定向到的文件中.

在我修复了.htaccess问题之后,我花了两个多小时试图修复它,即使我只是忘记了一些权限.


Fli*_*imm 6

设置环境变量并使用标头来接收它们:

您可以使用RewriteRule行创建新的环境变量,如OP所述:

RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html]
Run Code Online (Sandbox Code Playgroud)

但是,如果您无法使服务器端脚本工作,那么您如何阅读此环境变量?一种解决方案是设置标头:

Header set TEST_FOOBAR "%{REDIRECT_TEST0}e"
Run Code Online (Sandbox Code Playgroud)

该值接受格式说明符,包括%{NAME}e环境变量的说明符(不要忘记小写的e).有时候,你需要添加REDIRECT_前缀,但是当添加前缀时它没有计算出来,什么时候没有.


flm*_*flm 6

如果您要创建重定向,请使用curl进行测试以避免浏览器缓存问题。使用 -I 仅获取 http 标头。使用 -L 跟踪所有重定向。


Doi*_*oin 5

关于4.,在所有重写完成后,您仍然需要确保您的“虚拟脚本存根”实际上是目标URL,否则您将看不到任何内容!

一个类似/相关的技巧(参见这个问题)是插入一个临时规则,例如:

RewriteRule (.*) /show.php?url=$1 [END]
Run Code Online (Sandbox Code Playgroud)

哪里show.php有一些非常简单的脚本,只显示其$_GET参数(如果需要,您也可以显示环境变量)。

这将在您将其插入规则集中时停止重写,就像调试器中的断点一样。

如果您使用的是 Apache <2.3.9,则需要使用[L]而不是[END],然后可能需要添加:

RewriteRule ^show.php$ - [L]
Run Code Online (Sandbox Code Playgroud)

如果URL/show.php本身被重写,则位于规则集的最顶部。