首页 文章

调试.htaccess重写规则的提示

提问于
浏览
252

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

所以我的问题是,我们如何建议他们自己的规则 debug . 我在下面提供一些建议 . 其他建议将不胜感激 .

  • Understand that the mod_rewrite engine cycles through .htaccess files . 引擎运行此循环:
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 重写规则集 .

  • Make sure that the syntax of each Regexp is correct 通过对一组测试模式进行测试,以确保它是一个有效的语法,并完成你想要的全部测试URI . 有关详细信息,请参阅answer below .

  • Build up your rules incrementally in a test directory. 您可以使用“在路径功能上执行最深的 .htaccess 文件”来设置单独的测试目录(树)和调试规则集,而不会搞砸您的主要规则并停止您的站点工作 . 您必须一次添加一个,因为这是将故障本地化为单个规则的唯一方法 .

  • Use a dummy script stub to dump out server and environment variables . (请参阅 Listing 2 )如果您的应用使用 blog/index.php ,那么您可以将其复制到 test/blog/index.php 并使用它来测试 test 子目录中的博客规则 . 您还可以使用环境变量来确保重写引擎正确解释替换字符串,例如

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

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

  • Make sure that you don't get bitten by your browser caching incorrect 301 redirects . 见answer below . 我要感谢Ulrich Palha .

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

还有其他意见或建议吗?

清单1 - phpinfo

<?php phpinfo(INFO_ENVIRONMENT|INFO_VARIABLES);

14 回答

  • 3

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

  • 6

    我会把它留在这里,也许是显而易见的细节,但让我头几个小时:小心使用 %{REQUEST_URI} 因为@Krist van Besien在他的回答中说完全正确, but not for the REQUEST_URI string ,因为这个TestString的输出以 / 开头 . 所以要小心:

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

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

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

    RewriteRule (.*) /show.php?url=$1 [END]
    

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

    这将在您将其插入规则集的位置停止重写,而非调试器中的断点 .

    如果您需要使用 [L] 而不是 [END] ,那么您可能需要添加:

    RewriteRule ^show.php$ - [L]
    

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

  • 0

    (与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
    
  • 8

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

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

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

  • 4

    Make sure you use the percent sign in front of variables, not the dollar sign.

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

  • 3

    我观察到的一些错误发生在 .htaccess

    在多个规则中重复使用 ^(.*)$ ,使用 ^(.*)$ 会导致其他规则在大多数情况下无能为力,因为它匹配单击中的所有网址 .

    因此,如果我们使用此网址的规则 sapmle/url ,它也将使用此网址 sapmle/url/string .


    应该使用[L]标志来确保我们的规则已经完成处理 .


    应该知道:

    %n和$ n的差异

    %n%{RewriteCond} 部分匹配, $n%{RewriteRule} 部分匹配 .

    RewriteBase的工作

    RewriteBase指令指定用于替换相对路径的每个目录(htaccess)RewriteRule指令的URL前缀 . 除非满足以下任何条件,否则在每个目录(htaccess)上下文中使用替换中的相对路径时,此指令是必需的:原始请求和替换位于DocumentRoot下方(而不是通过其他方式可访问) ,如别名) . 包含RewriteRule的目录的文件系统路径(以相对替换为后缀)也可用作服务器上的URL路径(这种情况很少见) . 在Apache HTTP Server 2.4.16及更高版本中,当通过Alias或mod_userdir映射请求时,可能会省略此伪指令 .

  • 0

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

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

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

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

    Header set TEST_FOOBAR "%{REDIRECT_TEST0}e"
    

    accepts format specifiers,包括环境变量的 %{NAME}e 说明符(请't forget the lowercase e). Sometimes, you' ll需要添加 REDIRECT_ 前缀,但我没有't worked out when the prefix gets added and when it doesn' t .

  • 12

    Don't forget that in .htaccess files it is a relative URL that is matched.

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

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

    我在尝试调试我的mod_rewrite问题时发现了这个问题,它肯定有一些有用的建议 . 但最重要的是确保你的正则表达式语法正确 . 由于我自己的RE语法问题,安装regexpCheck.php脚本不是一个可行的选择 .

    但由于Apache使用Perl兼容的正则表达式(PCRE),任何有助于编写PCRE的工具都应该有所帮助 . 我过去曾使用过RegexPlanet的Java和Javascript RE工具,很高兴发现它们也支持Perl .

    只需输入您的正则表达式和一个或多个示例网址,它就会告诉您正则表达式是否匹配(“= =”列中的“1”)以及任何匹配的组(“拆分”中的数字)列将对应于Apache期望的数字,例如每个URL的$ 1,$ 2等 . 他们声称PCRE支持是“测试版”,但这正是我解决语法问题所需要的 .

    http://www.regexplanet.com/advanced/perl/index.html

    我只是简单地对现有答案添加了评论,但我的声誉还没有达到那个级别 . 希望这有助于某人 .

  • 6

    如果您打算在.htacesss中编写多行规则,
    甚至不考虑尝试其中一种热修复方法来调试它 .

    我没有浪费时间来设置多个规则而没有来自LOG的反馈,只是最终放弃了一个 .
    我在我的电脑上安装了Apache,将整个站点复制到硬盘驱动器,然后使用日志快速整理整个规则集 .
    然后我回顾了我的旧规则,我看到他们并没有真正做到所需的 . 一个不同地址的定时炸弹 .

    在重写规则中存在很多陷阱,它根本不是一个直接逻辑的东西 .
    您可以在十分钟内启动并运行Apache,它是10MB,良好的许可证,* NIX / WIN / MAC准备就绪,即使没有安装 .
    另外,检查服务器的 Headers 行,如果旧的则从归档中获取相同版本的Apache . 我的OP仍然在2.0,很多东西都不支持 .

  • 1

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

    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 . DON'T .

    如果您不在您的网站上使用建议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有害,需要修复 .

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


  • 124

    确保每个Regexp的语法正确

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

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

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

    在线.htaccess重写测试

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

    来自网站:

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

相关问题