apache、lighttpd和Nginx的404错误处理

最近在处理图片分布问题,问题来源是这样的:
1 把服务器B的图片定时同步到服务器A,用A来接受用户访问
2 同步有时间差,为了保证用户体验,需要在A发生404错误的时候转移到原服务器B,这样用户体会不到发生问题,否则上传图片会立刻看不到,不可能等你同步完的

我觉得这样的分布方式应该是很不错的,只要解决404错误的处理,就可以保证上面的服务正常。因为是说明问题,所以以下提及的代码都整理过,域名也做了更改。

一、最初用lighttpd来处理:

发生404错误,则交由cgi脚本来处理,取得$REQUEST_URI,location到源服务器

404.cgi脚本文件(比较简单,需要条件性的转移请自行修改):

 

#!/bin/sh

# disable filename globbing
set -f

URI=$REQUEST_URI

## by hqlulu @ aslibra.com 2008-8-14 ##
echo "location: http://www.aslibra.com$URI"
echo

Lighttpd下使用cgi测试:

 

#配置如下:
server.error-handler-404 = "/cgi-bin/404.cgi"

http://test404.aslibra.com/mag/nofile
得到的是www.aslibra.com的404错误提示,说明已经转移成功

测试结果:
 

引用
[root@gx ~]# curl -I http://test404.aslibra.com/mag/nofile
HTTP/1.1 302 Found
Expires: Tue, 02 Sep 2008 12:52:44 GMT
Cache-Control: max-age=864000
location: http://www.aslibra.com/mag/nofile
Date: Sat, 23 Aug 2008 12:52:44 GMT
Server: lighttpd/1.4.15

二、Apache安装在8080端口,尝试cgi失败了:

 

#配置如下:
ErrorDocument 404 "/cgi-bin/404.cgi"

http://test404.aslibra.com:8080/mag/nofile
看到的是空白页面

测试结果:
 

引用
[root@gx ~]# curl -I http://test404.aslibra.com:8080/mag/nofile
HTTP/1.1 404 Not Found
Date: Sat, 23 Aug 2008 12:55:45 GMT
Server: Apache/2.2.6 (Unix)
location: http://www.aslibra.com/mag/nofile
Connection: close
Content-Type: text/plain

琢磨了很久,才发现问题,可以看到原因,已经发出了404错误的文件头了,导致后面的location失效,但是怎么去掉404的输出呢,让我纳闷了很久。

经过查实Apache的文档:

 

引用
如果ErrorDocument指定了一个到本地CGI脚本的重定向,该脚本应当在它的输出中包含一个"Status:"头字段以确保将导致调用它的错误条件始终返回客户端。举例来说,一个Perl ErrorDocument脚本可能包含如下内容:

print "Content-type: text/html\n";
printf "Status: %s <中断条件>\n", $ENV{"REDIRECT_STATUS"};

如果该脚本专门用于处理一个特定的错误条件,比如:404 Not Found ,它就可以使用特定的代码和错误文本进行替代。

需要注意的是如果应答包含一个"Location:"头(为了进行一个客户端重定向),脚本必须发出一个适当的"Status:"头(比如:302 Found)。否则"Location:"头可能无效。

这就找到原因了,加上一段就可以了:

 

#!/bin/sh

# disable filename globbing
set -f

URI=$REQUEST_URI
echo "Status:302 Found"

## by hqlulu @ aslibra.com 2008-8-14 ##
echo "location: http://www.aslibra.com$URI"
echo

测试结果:
 

引用
[root@gx ~]# curl -I http://test404.aslibra.com:8080/mag/nofile
HTTP/1.1 302 Found
Date: Sat, 23 Aug 2008 13:02:54 GMT
Server: Apache/2.2.6 (Unix)
location: http://www.aslibra.com/mag/nofile
Connection: close
Content-Type: text/plain

三、Apache的PHP处理方式(安装了PHP的模块):

 

ErrorDocument 404 /404.php

404.php文件内容(条件转移自行修改):
 

<?php
$url=$_SERVER[REQUEST_URI];
header("location: http://www.aslibra.com".$url);
?>

测试结果:
 

引用
[root@gx ~]# curl -I http://pic.zcom.com/mag/nofile
HTTP/1.1 302 Found
Date: Sat, 23 Aug 2008 13:10:14 GMT
Server: Apache/2.2.6 (Unix) PHP/5.2.6
X-Powered-By: PHP/5.2.6
location: http://www.aslibra.com/mag/nofile
Content-Type: text/html

四、Nginx的配置:

因为Nginx没法使用cgi,只能使用fastcgi,所以配置了PHP的fastcgi处理404错误。

 

error_page  404              /404.php;

location ~ \.php$ {
    fastcgi_pass   192.168.1.5:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  /Data/webapps/www.aslibra.com$fastcgi_script_name;
    include        fastcgi_params;
}

测试结果:
 

引用
[root@gx ~]# curl -I http://test404.aslibra.com:88/mag/nofile
HTTP/1.1 404 Not Found
Server: nginx/0.6.31
Date: Sat, 23 Aug 2008 13:10:42 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.2.6
location: http://www.aslibra.com/mag/nofile

碰到了apache的一样的问题,于是查看官方说明的错误处理:

 

引用
error_page
syntax: error_page code [ code... ] [ = |=answer-code ] uri

default: no

context: http, server, location, if in location

The directive specifies the URI, which will be showed for the errors indicated.

Example of the use:

error_page   404          /404.html;
error_page   502 503 504  /50x.html;
error_page   403          http://example.com/forbidden.html;
Furthermore, it is possible to change the code of answer to another, for example:

error_page 404 =200 /.empty.gif;
If an erroneous answer is processed by the proxied or FastCGI server and this server can return the different answer codes, for example, 200, 302, 401 or 404, then it is possible to issue the code returned:

error_page   404  =  /404.php;

终于看到这个例子了:
error_page 404 =200 /.empty.gif;

也就是指定一个answer-code就正常了,修改配置:
 

error_page  404 =302             /404.php;

location ~ \.php$ {
    fastcgi_pass   192.168.1.5:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  /Data/webapps/www.aslibra.com$fastcgi_script_name;
    include        fastcgi_params;
}

测试结果:
 

引用
[root@gx ~]# curl -I http://test404.aslibra.com:88/mag/nofile
HTTP/1.1 302 Moved Temporarily
Server: nginx/0.6.31
Date: Sat, 23 Aug 2008 13:15:20 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.2.6
location: http://www.aslibra.com/mag/nofile

这回就正常了!

以上是常见的三种web服务器的404错误处理,希望可以对解决大家的应用问题有参考价值。

五、404.cgi的条件判断(代码有点笨,sh不是专长):

 

#!/bin/sh

# disable filename globbing
set -f

URI=$REQUEST_URI
echo "Status:302 Found"

if
  echo $URI | grep "^/mag" >/dev/null
then
        echo "location: http://www1.aslibra.com$URI"
elif
  echo $URI | grep "^/op" >/dev/null
then
        echo "location: http://www2.aslibra.com$URI"
else
        echo
        echo "file not exists!"
fi

此条目发表在web server分类目录,贴了, , 标签。将固定链接加入收藏夹。