最近在处理图片分布问题,问题来源是这样的:
1 把服务器B的图片定时同步到服务器A,用A来接受用户访问
2 同步有时间差,为了保证用户体验,需要在A发生404错误的时候转移到原服务器B,这样用户体会不到发生问题,否则上传图片会立刻看不到,不可能等你同步完的
我觉得这样的分布方式应该是很不错的,只要解决404错误的处理,就可以保证上面的服务正常。因为是说明问题,所以以下提及的代码都整理过,域名也做了更改。
一、最初用lighttpd来处理:
发生404错误,则交由cgi脚本来处理,取得$REQUEST_URI,location到源服务器
404.cgi脚本文件(比较简单,需要条件性的转移请自行修改):
# 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错误提示,说明已经转移成功
测试结果:
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
看到的是空白页面
测试结果:
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的文档:
print "Content-type: text/html\n";
printf "Status: %s <中断条件>\n", $ENV{"REDIRECT_STATUS"};
如果该脚本专门用于处理一个特定的错误条件,比如:404 Not Found ,它就可以使用特定的代码和错误文本进行替代。
需要注意的是如果应答包含一个"Location:"头(为了进行一个客户端重定向),脚本必须发出一个适当的"Status:"头(比如:302 Found)。否则"Location:"头可能无效。
这就找到原因了,加上一段就可以了:
# 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
测试结果:
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的模块):
404.php文件内容(条件转移自行修改):
$url=$_SERVER[REQUEST_URI];
header("location: http://www.aslibra.com".$url);
?>
测试结果:
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错误。
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;
}
测试结果:
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的一样的问题,于是查看官方说明的错误处理:
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就正常了,修改配置:
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;
}
测试结果:
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不是专长):
# 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