如何调试Apache的400错误

诱发原因

此处我们默认导致400的原因是由于我们写rewrite规则错误导致的400错误。所谓400错误就是不合法的请求,意思是服务端已经不知道你请求一个域名加一个路径的含义了。

解决办法

mod_rewite模块支持很多指令,大家可以参考http://blog.chinaunix.net/uid-20639775-id-154471.html。只需要从其中配置上Apache处理rewrite的过程的日志即可,以我实际碰到的一个bug为例,之前的rewrite规则大概是这样的,通过.htaccess文件。

RewriteEngine On

# Some hosts may require you to use the `RewriteBase` directive.
# If you need to use the `RewriteBase` directive, it should be the
# absolute physical path to the directory that contains this htaccess file.
#
# RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]

这个rewrite规则很简单,意思就是把所有的请求都rewrite到index.php脚本处理,但是实际并不是这样,访问的时候一直报400错误,那是什么原因导致的呢,通过在vhost文件的rewrite模块加日志。参见下面的加法:

<IfModule rewrite_module>
        RewriteEngine On
        RewriteLog /data0/logs/rewrite_log
        RewriteLogLevel 9
    </IfModule>

注意看到RewriteLog和RewriteLogLevel,一定要将其等级设置为9才能看到详细的log,这时候我们让Apache重新加载模块 apachectl -k graceful,然后等待日志可以看到:

10.217.88.69 - - [28/Dec/2015:13:28:20 +0800] [op.admin.sae.sina.com.cn/sid#7f4a8b755ca0][rid#7f4a8bcf3338/initial] (2) [perdir /data1/www/htdocs/op.admin.sae.sina.com.cn/] rewrite 'api/login' -> 'index.php'
10.217.88.69 - - [28/Dec/2015:13:28:20 +0800] [op.admin.sae.sina.com.cn/sid#7f4a8b755ca0][rid#7f4a8bcf3338/initial] (3) [perdir /data1/www/htdocs/op.admin.sae.sina.com.cn/] add per-dir prefix: index.php -> /data1/www/htdocs/op.admin.sae.sina.com.cn/index.php
10.217.88.69 - - [28/Dec/2015:13:28:20 +0800] [op.admin.sae.sina.com.cn/sid#7f4a8b755ca0][rid#7f4a8bcf3338/initial] (2) [perdir /data1/www/htdocs/op.admin.sae.sina.com.cn/] strip document_root prefix: /data1/www/htdocs/op.admin.sae.sina.com.cn/index.php -> /index.php
10.217.88.69 - - [28/Dec/2015:13:28:20 +0800] [op.admin.sae.sina.com.cn/sid#7f4a8b755ca0][rid#7f4a8bcf3338/initial] (1) [perdir /data1/www/htdocs/op.admin.sae.sina.com.cn/] internal redirect with /index.php [INTERNAL REDIRECT]
10.217.88.69 - - [28/Dec/2015:13:28:20 +0800] [op.admin.sae.sina.com.cn/sid#7f4a8b755ca0][rid#7f4a8bcfb7c8/initial/redir#1] (2) init rewrite engine with requested uri /index.php
10.217.88.69 - - [28/Dec/2015:13:28:20 +0800] [op.admin.sae.sina.com.cn/sid#7f4a8b755ca0][rid#7f4a8bcfb7c8/initial/redir#1] (1) pass through /index.php
10.217.88.69 - - [28/Dec/2015:13:28:20 +0800] [op.admin.sae.sina.com.cn/sid#7f4a8b755ca0][rid#7f4a8bcfb7c8/initial/redir#1] (3) [perdir /data1/www/htdocs/op.admin.sae.sina.com.cn/] strip per-dir prefix: /data1/www/htdocs/op.admin.sae.sina.com.cn/index.php -> index.php
10.217.88.69 - - [28/Dec/2015:13:28:20 +0800] [op.admin.sae.sina.com.cn/sid#7f4a8b755ca0][rid#7f4a8bcfb7c8/initial/redir#1] (3) [perdir /data1/www/htdocs/op.admin.sae.sina.com.cn/] applying pattern '^' to uri 'index.php'
10.217.88.69 - - [28/Dec/2015:13:28:20 +0800] [op.admin.sae.sina.com.cn/sid#7f4a8b755ca0][rid#7f4a8bcfb7c8/initial/redir#1] (4) [perdir /data1/www/htdocs/op.admin.sae.sina.com.cn/] RewriteCond: input='/data1/www/htdocs/op.admin.sae.sina.com.cn/index.php' pattern='!-f' => not-matched
10.217.88.69 - - [28/Dec/2015:13:28:20 +0800] [op.admin.sae.sina.com.cn/sid#7f4a8b755ca0][rid#7f4a8bcfb7c8/initial/redir#1] (1) [perdir /data1/www/htdocs/op.admin.sae.sina.com.cn/] pass through /data1/www/htdocs/op.admin.sae.sina.com.cn/index.php

如此就可以看到各种内部的转跳[INTERNAL REDIRECT],快速的定位rewrite规则了。