Many posters have problems debugging their RewriteRule and RewriteCond statements within their .htaccess files. Most of these are using a shared hosting service and therefore don't have access to the root server configuration. They cannot avoid using .htaccess files for rewriting and cannot enable a RewriteLogLevel" as many respondents suggest. Also there are many .htaccess-specific pitfalls and constraints are aren't covered well. Setting up a local test LAMP stack involves too much of a learning curve for most.

所以我的问题是我们建议他们如何自己调试他们的规则。以下是我的一些建议。其他建议将不胜感激。

Understand that the mod_rewrite engine cycles through .htaccess files. The engine runs this loop: 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 So your rules will get executed repeatedly and if you change the URI path then it may end up executing other .htaccessfiles if they exist. So make sure that you terminate this loop, if necessary by adding extra RewriteCond to stop rules firing. Also delete any lower level .htaccess rewrite rulesets unless explicitly intent to use multi-level rulesets. Make sure that the syntax of each Regexp is correct by testing against a set of test patterns to make sure that is a valid syntax and does what you intend with a fully range of test URIs. See answer below for more details. Build up your rules incrementally in a test directory. You can make use of the "execute the deepest .htaccess file on the path feature" to set up a separate test directory (tree) and debug rulesets here without screwing up your main rules and stopping your site working. You have to add them one at a time because this is the only way to localise failures to individual rules. Use a dummy script stub to dump out server and environment variables. (See Listing 2)If your app uses, say, blog/index.php then you can copy this into test/blog/index.php and use it to test out your blog rules in the test subdirectory. You can also use environment variables to make sure that the rewrite engine in interpreting substitution strings correctly, e.g. RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html] and look for these REDIRECT_* variables in the phpinfo dump. BTW, I used this one and discovered on my site that I had to use %{ENV:DOCUMENT_ROOT_REAL} instead. In the case of redirector looping REDIRECT_REDIRECT_* variables list the previous pass. Etc.. Make sure that you don't get bitten by your browser caching incorrect 301 redirects. See answer below. My thanks to Ulrich Palha for this. The rewrite engine seems sensitive to cascaded rules within an .htaccess context, (that is where a RewriteRule results in a substitution and this falls though to further rules), as I found bugs with internal sub-requests (1), and incorrect PATH_INFO processing which can often be prevents by use of the [NS], [L] and [PT] flags.

还有什么评论或建议吗?

清单1——phpinfo

<?php phpinfo(INFO_ENVIRONMENT|INFO_VARIABLES);

当前回答

我把这个留在这里,也许是明显的细节,但让我敲了几个小时的头: 小心使用%{REQUEST_URI},因为@Krist van Besien在他的回答中说的是完全正确的,但不是REQUEST_URI字符串,因为这个TestString的输出以/开头。所以要小心:

RewriteCond %{REQUEST_URI} ^/assets/$  
                            ^
                            | check this pesky fella right here if missing

其他回答

不要忘记,在.htaccess文件中,它是一个相对URL匹配。

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

RewriteRule ^/(.*)     /something/$s

确保在变量前面使用百分号,而不是美元号。

它是%{HTTP_HOST},不是${HTTP_HOST}。在error_log中什么也没有,也没有内部服务器错误,您的regexp仍然是正确的,规则只是不匹配。如果你经常使用django / genshi模板,并且在肌肉内存中使用${}作为变量替换,这真的很可怕。

确保每个Regexp的语法是正确的

通过对一组测试模式进行测试,以确保语法有效,并对所有测试uri执行您想要的操作。

See regexpCheck.php below for a simple script that you can add to a private/test directory in your site to help you do this. I've kept this brief rather than pretty. Just past this into a file regexpCheck.php in a test directory to use it on your website. This will help you build up any regexp and test it against a list of test cases as you do so. I am using the PHP PCRE engine here, but having had a look at the Apache source, this is basically identical to the one used in Apache. There are many HowTos and tutorials which provide templates and can help you build your regexp skills.

清单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>

也许调试重写规则的最好方法是根本不使用重写规则,而是将URL处理从htaccess文件推迟到PHP文件(让我们称之为router.php)。然后,您可以使用PHP进行任何您喜欢的操作,并使用适当的错误检测和常规的调试方法。这甚至运行得更快,因为您不必使用重写模块。

对于文件系统中没有的URL,要立即将控制权从.htaccess转移到router.php,只需在.htaccess中放入以下一行:

FallbackResource router.php

是的,真的很简单。是的,它确实有效。试一试。

注意:你可能需要在你的。htaccess文件中使用一个ErrorDocument指令来在HTTP状态404时显式地将某些url的控制权传递给你的router.php文件,特别是如果你继承了处理状态404的父htaccess文件。这样一来,将控制权传递到路由器文件总共需要两行。

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

如果你已经应用了所有这些技巧,但因为你没有访问服务器错误日志而只出现了500个错误,也许问题不在.htaccess文件中,而在它重定向到的文件中。

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