优化Error 404页面

2条评论

虽然我们尽一切努力确保网站上每个链接的有效性,让它们指向特定的网页,但漏网之鱼总是存在的,于是在点击无效链接后,鼎鼎大名的404错误页面—— 404 ERROR PAGE NOT FOUND(404错误:页面未找到)就出现了。

当然404错误页面也不是一无是处。聪明的WordPress网站管理者会在其访问者遇到404错误页面时,在页面上显示一些有用的信息,而不仅仅是“NOT FOUND”。

在这篇文章中,我们要告诉大家怎样修改“error”和“page not found”信息,为访问者提供更有价值的资料。同时还要向大家展示怎样确保网络服务器能够正确显示我们所修改的信息,最后,我们会介绍怎样创建一个与主题风格一致的404错误页面。

链接确认

有些错误是可以避免的。定期检查自己网站上的所有链接。如果需要删除某篇很受欢迎但已经过期的文章,可以考虑删除文章正文,然后在文章中添加一条链接,将访问者导向到新页面。

了解网络错误处理机制

即使最高级最优秀的网站也可能出现错误。作为网站管理员,我们会不时删除一些过期文章,但其它网站中可能仍然存在这些文章的链接。

如果访问者点击的链接指向的是已经不存在的页面,web服务器会将相应的错误信息发送给访问者,404 Not Found就是其中一种错误信息。除非网站管理员事先设置了错误信息的显示内容和方式,否则访问者看到的都是以普通文本形式显示的标准错误信息。虽然标准,却难免让人有些失落。

看到错误页面后,很多访问者会直接按下后退键,如果他们不在意在我们的网站上查找信息所浪费的时间,把注意力转移到其它网站上,那么我们就失去了一批潜在读者。为了留住这些访问者,我们至少需要重新设定错误信息,在错误页面上提供一个指向我们网站首页的链接。

礼貌的错误信息处理方式是,承认错误的存在并帮助访问者找到自己需要的资料。这包括创建一个自定义错误页面,或是修改WordPress主题中自带的错误页面。

修改Error 404页面

WordPress默认主题附带404.php文件,但不是所有主题都具备自定义的404错误模板文件。主题自带的404错误模板文件的文件名一般都是404.php。如果网站出现Page Not Found的情况,WordPress会自动调用404.php文件。

主题中的标准404.php页面能够正常运行,但这些标准页面显示的内容未必是我们需要的内容,也未必能够提供我们希望提供给访问者的帮助,这时我们就会考虑在模板文件中重新设计404错误页面。

我们可以根据以下步骤修改主题中的404错误模板文件:

1. 打开WordPress控制板

2. 选择“设计”菜单(WP 2.5后更名为“外观”)

3. 在菜单下选择“编辑”选项

4. 查找主题的文件列表中是否包含“404页面模板”

5. 在页面右边点击“404页面模板”链接

6. 根据自己的需要更改404文本信息

7. 保存所做改动(遇到无法写入的模板文件时请参考更改文件权限

检查并修改404模板文件时,可以顺便了解一下默认404.php文件的结构。该文件主要由各种标签(负责显示页眉、侧边栏、页脚)与一个显示404错误信息的区域组成:

<?php get_header(); ?>
   <div id="content" class="narrowcolumn">
     <h2 class="center">Error 404 - Not Found</h2>
	</div>
<?php get_sidebar(); ?>
<?php get_footer(); ?>

为了改变访问者看见的错误信息,我们需要修改h2标题字号中的文字,必要时可以加入多段文字。

创建Error 404页面

如果当前WordPress主题中没有404.php模板文件,我们可以为主题设计一个404错误页面。

没有哪两个主题是完全相同的,所以我们不能保证WordPress的Default主题中的404.php模板文件在其它主题中也一定可以运行,但我们可以试着从这里开始404页面的创建过程。将Default主题中的错误页面复制到当前主题中后,错误页面也呈现出当前主题的风格,这是因为它已经调用了当前主题的页眉和页脚。这就节省了我们的时间,接下来只需要按照自己的需要更改错误信息。

如何使用WordPress的Default主题中的404.php模板文件:

1. 将/wp-content/themes/default/404.php文件复制到当前主题目录下

2. 根据上一个章节的描述,根据自己的需要编辑错误信息

如果复制过来的404.php文件不能在当前主题中正常运行,可以试试下面的方法:

  • 修改Default主题的404.php模板文件的页眉、侧边栏、页脚或其它代码,使之匹配当前主题布局

  • 将当前主题的Index.php文件复制到404.php文件中
  • 打开404.php文件,删除其中所有关于日志或评论的内容,参见WordPress主循环
  • 最后,修改错误信息

404.php高级示例

下面这个例子展示了WordPress 404.php页面和HTTP状态码操作的技术高度。我们也应该尽最大努力让404页面为访问者提供更有效的信息,尽可能将断链重定向到正确位置上。

AskApache Google 404 Plugin插件能够处理404.php模板文件所处理的其它类型错误状态码。

插件决定服务器错误信息的类型,这样我们就可以为非404错误提供准确的http反应,不必浪费带宽和CPU。插件也能够根据HTTP状态码和 RFC 2616 specifications中的规定尽力提供正确反应。

<?php
 
$ASKAPACHE_S_C = array(
'400' => array(
  'Bad Request', 
  'Your browser sent a request that this server could not understand.'),
'401' => array(
  'Authorization Required', 
  'This server could not verify that you are authorized to '.
  'access the document requested. Either you supplied the '.
  'wrong credentials (e.g., bad password), or your browser '.
  'doesn\'t understand how to supply the credentials required.'),
'402' => array(
  'Payment Required', 
  'INTERROR'),
'403' => array(
  'Forbidden', 
  'You don\'t have permission to access THEREQUESTURI on this '.
  'server.'),
'404' => array(
  'Not Found', 
  'We couldn\'t find <acronym title="THEREQUESTURI">that uri'.
  '</acronym> on our server, though it\'s most certainly not '.
  'your fault.'),
'405' => array(
  'Method Not Allowed', 
  'The requested method THEREQMETH is not allowed for the URL '.
  'THEREQUESTURI.'),
'406' => array(
  'Not Acceptable', 
  'An appropriate representation of the requested resource '.
  'THEREQUESTURI could not be found on this server.'),
'407' => array(
  'Proxy Authentication Required', 
  'This server could not verify that you are authorized to '.
  'access the document requested. Either you supplied the wrong '.
  'credentials (e.g., bad password), or your browser doesn\'t '.
  'understand how to supply the credentials required.'),
'408' => array(
  'Request Time-out', 
  'Server timeout waiting for the HTTP request from the client.'),
'409' => array(
  'Conflict', 
  'INTERROR'),
'410' => array(
  'Gone', 
  'The requested resourceTHEREQUESTURIis no longer available on '.
  'this server and there is no forwarding address. Please remove '.
  'all references to this resource.'),
'411' => array(
  'Length Required', 
  'A request of the requested method GET requires a valid '.
  'Content-length.'),
'412' => array(
  'Precondition Failed', 
  'The precondition on the request for the URL THEREQUESTURI '.
  'evaluated to false.'),
'413' => array(
  'Request Entity Too Large', 
  'The requested resource THEREQUESTURI does not allow request '.
  'data with GET requests, or the amount of data provided in the '.
  'request exceeds the capacity limit.'),
'414' => array(
  'Request-URI Too Large', 
  'The requested URL\'s length exceeds the capacity limit for '.
  'this server.'),
'415' => array(
  'Unsupported Media Type', 
  'The supplied request data is not in a format acceptable for '.
  'processing by this resource.'),
'416' => array(
  'Requested Range Not Satisfiable', 
  ''),
'417' => array(
  'Expectation Failed', 
  'The expectation given in the Expect request-header field could '.
  'not be met by this server. The client sent <code>Expect:</code>'),
'422' => array(
  'Unprocessable Entity', 
  'The server understands the media type of the request entity, but '.
  'was unable to process the contained instructions.'),
'423' => array(
  'Locked', 
  'The requested resource is currently locked. The lock must be released '.
  'or proper identification given before the method can be applied.'),
'424' => array(
  'Failed Dependency', 
  'The method could not be performed on the resource because the requested '.
  'action depended on another action and that other action failed.'),
'425' => array(
  'No code', 
  'INTERROR'),
'426' => array(
  'Upgrade Required', 
  'The requested resource can only be retrieved using SSL. The server is '.
  'willing to upgrade the current connection to SSL, but your client '.
  'doesn\'t support it. Either upgrade your client, or try requesting '.
  'the page using https://'),
'500' => array(
  'Internal Server Error', 
  'INTERROR'),
'501' => array(
  'Method Not Implemented', 
  'GET to THEREQUESTURI not supported.'),
'502' => array(
  'Bad Gateway', 
  'The proxy server received an invalid response from an upstream server.'),
'503' => array(
  'Service Temporarily Unavailable', 
  'The server is temporarily unable to service your request due to '.
  'maintenance downtime or capacity problems. Please try again later.'),
'504' => array(
  'Gateway Time-out', 
  'The proxy server did not receive a timely response from the '.
  'upstream server.'),
'505' => array(
  'HTTP Version Not Supported', 
  'INTERROR'),
'506' => array(
  'Variant Also Negotiates', 
  'A variant for the requested resource <code>THEREQUESTURI</code> '.
  'is itself a negotiable resource. This indicates a configuration error.'),
'507' => array(
  'Insufficient Storage', 
  'The method could not be performed on the resource because the '.
  'server is unable to store the representation needed to successfully '.
  'complete the request. There is insufficient free space left in your '.
  'storage allocation.'),
'510' => array(
  'Not Extended', 
  'A mandatory extension policy in the request is not accepted by the '.
  'server for this resource.')
);
 
 

// prints out the html for the error, taking the status code as input
function aa_print_html ($AA_C){
    global $AA_REQUEST_METHOD, $AA_REASON_PHRASE, $AA_MESSAGE;
    
    if($AA_C == '400'||$AA_C == '403'||$AA_C == '405'||$AA_C[0] == '5'){
        @header("Connection: close",1);
        
        if($AA_C=='405')@header('Allow: GET,HEAD,POST,OPTIONS,TRACE');
        
        echo "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>";
        echo "<title>$AA_C $AA_REASON_PHRASE</title>";
        echo "<h1>$AA_REASON_PHRASE</h1>\n<p>$AA_MESSAGE<br>\n</p>\n</body></html>";
        return true;
    } else return false;
}


// Tries to determine the error status code encountered by the server
if(!isset($_REQUEST['error']))  $AA_STATUS_CODE = '404';
else  $AA_STATUS_CODE = $_REQUEST['error'];

if(isset($_SERVER['REDIRECT_STATUS']) && $_SERVER['REDIRECT_STATUS']!='200') 
$AA_STATUS_CODE = $_SERVER['REDIRECT_STATUS'];
 
 
$AA_REQUEST_METHOD = $_SERVER['REQUEST_METHOD'];
$AA_THE_REQUEST = htmlentities(strip_tags($_SERVER['REQUEST_URI']));
$AA_REASON_PHRASE = $ASKAPACHE_S_C[$AA_STATUS_CODE][0];
$AA_M_SR=array(array('INTERROR','THEREQUESTURI','THEREQMETH'),
array('The server encountered an internal error or misconfiguration '.
'and was unable to complete your request.',$AA_THE_REQUEST,$AA_REQUEST_METHOD));
$AA_MESSAGE=str_replace($AA_M_SR[0],$AA_M_SR[1],$ASKAPACHE_S_C[$AA_STATUS_CODE][1]);


// begin the output buffer to send headers and resonse
ob_start();
@header("HTTP/1.1 $AA_STATUS_CODE $AA_REASON_PHRASE",1);
@header("Status: $AA_STATUS_CODE $AA_REASON_PHRASE",1);

if(!aa_print_html($AA_STATUS_CODE)){
    ?>
    <?php get_header();?>
    <div id="content">
    <div class="post">
    <h1><?php _e("$AA_STATUS_CODE $AA_REASON_PHRASE"); ?></h1>
    <?php if(function_exists('aa_google_404')) aa_google_404(); ?>
    </div>
    </div>
    <?php get_sidebar(); ?>
    <?php get_footer(); ?>
<?php } 
exit; exit();
?>

改进错误页面小技巧

有很多方法可以改善404错误页面,下面介绍其中几种。

传送准确的页头信息

默认情况下WordPress按照正常网页形式传输404页面。为了让Google等搜索引擎正确索引404页面,我们可以在当前主题404.php文件的最上方加入以下代码。

注意:在最新版本的WordPress无需进行此操作。

<?php header("HTTP/1.1 404 Not Found"); ?>  
<?php header("Status: 404 Not Found"); ?>  

有时还需要在上述代码前加入以下代码:

<?php ob_start(); ?>  

编写友好的错误信息

我们可以在错误页面上显示各种内容,告诉读者,他们遇到的只是一个很小的问题,我们正尽最大努力帮助他们查找他们需要的信息。例如,我们可以这样说:

"Oops, I screwed up and you discovered my fatal flaw. 
Well, we're not all perfect, but we try.  Can you try this
again or maybe visit our <a 
title="Our Site" href="http://example.com/index.php">Home 
Page</a> to start fresh.  We'll do better next time."

同时还要尝试找出用户真正需要的信息。下载 AskApache Google 404 Plugin插件,为404.php页面添加Google搜索结果。

当然也可以说一些简短而亲切的话。无论怎样,几乎所有都比404 Error Page Not Found看上去要好的多。在互联网上可以找到很多编写404错误页面的资料,比如 List Apart's Perfect 404

作为一个完美的404页面,List Apart's Perfect 404告诉访问者,出现这个页面并不是他们的错,如果的确是由他们的错误导致404页面出现,请发送电子邮件给网站管理员描述详细情况。

404页面有时非常恼人,也没有帮助性。利用WordPress工具可以削弱404页面的负面影响,给访问者带来有价值有帮助的信息,同时访问者通过某个链接来到一个实际并不存在的页面时,如果能给我们邮件通知,这对我们也有很大帮助。

<p>You 
<?php
#some variables for the script to use
#if you have some reason to change these, do.  but wordpress can handle it
$adminemail = get_bloginfo('admin_email'); #the administrator email address, according to wordpress
$website = get_bloginfo('url'); #gets your blog's url from wordpress
$websitename = get_bloginfo('name'); #sets the blog's name, according to wordpress

  if (!isset($_SERVER['HTTP_REFERER'])) {
    #politely blames the user for all the problems they caused
        echo "tried going to "; #starts assembling an output paragraph
	$casemessage = "All is not lost!";
  } elseif (isset($_SERVER['HTTP_REFERER'])) {
    #this will help the user find what they want, and email me of a bad link
	echo "clicked a link to"; #now the message says You clicked a link to...
        #setup a message to be sent to me
	$failuremess = "A user tried to go to $website"
        .$_SERVER['REQUEST_URI']." and received a 404 (page not found) error. ";
	$failuremess .= "It wasn't their fault, so try fixing it.  
        They came from ".$_SERVER['HTTP_REFERER'];
	mail($adminemail, "Bad Link To ".$_SERVER['REQUEST_URI'],
        $failuremess, "From: $websitename <noreply@$website>"); #email you about problem
	$casemessage = "An administrator has been emailed 
        about this problem, too.";#set a friendly message
  }
  echo " ".$website.$_SERVER['REQUEST_URI']; ?> 
and it doesn't exist. <?php echo $casemessage; ?>  You can click back 
and try again or search for what you're looking for:
  <?php include(TEMPLATEPATH . "/searchform.php"); ?>
</p>

添加实用链接

WordPress官方网站上遇到“页面未找到”页面时,页面上会显示该网站内多个链接,将用户指向其它分类信息。404页面地址——http://wordpress.org/brokenlink.php

如果我们要在404页面上添加类似的实用链接,只要新建一个链接列表或一段文字,访问者可以从中选择自己需要的链接。这比把访问者带到死角上要好多了。怎样让404页面上的链接指向网站中的文档,尤其是页面和分类文档,请看内容链接

测试404错误信息

在浏览器中输入一个并不存在于我们网站上的URL,测试之前生成的自定义404页面和信息的运行情况。可以试着输入下面的URL:

http://example.com/fred.php  

除非我们的网站上的确有一个叫做fred的php文件,否则浏览器会直接导向到错误页面。如果觉得错误页面看起来有些别扭,可以返回重新修改错误信息,使之符合主题布局和风格。

帮助服务器查找404页面

默认情况下,如果WordPress查找某页面未果,会用404.php页面来代替。尽管如此,有时web服务器也会出错,在WordPress没有察觉服务器的错误前,我们需要设置服务器以运行自定义404页面,确保web服务器将404.php模板文件传送到访问者端。

要让服务器使用自定义错误文件,需要在WordPress主目录(index.php文件所在目录)下编辑 .htaccess文件。如果没有 .htaccess文件,请参考使用WordPress固定链接对创建 .htaccess文件的介绍。

.htaccess文件中加入以下代码行,确保服务器能够顺利找到404页面:

ErrorDocument 404 /index.php?error=404

url/index.php文件是相对于根目录的相对路径,表示左斜线后的内容开始于网站根文件夹。如果WordPress被安装在网站根文件夹的子文件夹或子目录中,并且被命名为wordpress,请在.htaccess文件中加入以下代码:

ErrorDocument 404 /wordpress/index.php?error=404

其它错误码处理

  • 本部分内容没有实际用途,无需掌握,仅供练习

尽可能多使用静态错误文档,这是因为要处理一张并不存在(404 Not Found)的图片,单个/missing.html文件比/index.php?error=404占用的CPU和容量都要少得多。

我们可以用下面的代码行来激活WordPress的404.php模板文件,让404.php同时处理其他服务器错误。

注意:有些服务器错误由WordPress处理,有些错误则输出静态.html文档,还有些错误是php脚本错误。例如,500错误不应由WordPress处理,因为500错误可能是由WordPress引发的(例如由一个有瑕疵的插件引发)。因此我们需要指导服务器输出有帮助价值的静态.html文档。

ErrorDocument 400 /cgi-bin/error-deal.php
ErrorDocument 402 /cgi-bin/error-deal.php
ErrorDocument 403 /error/403/index.html
ErrorDocument 404 /index.php?error=404
ErrorDocument 405 /error/405/index.php
ErrorDocument 406 /index.php?error=406
ErrorDocument 407 /index.php?error=407
ErrorDocument 408 /index.php?error=408
ErrorDocument 409 /index.php?error=409
ErrorDocument 410 /index.php?error=410
ErrorDocument 411 /index.php?error=411
ErrorDocument 412 /index.php?error=412
ErrorDocument 413 /index.php?error=413
ErrorDocument 414 /index.php?error=414
ErrorDocument 415 /index.php?error=415
ErrorDocument 416 /index.php?error=416
ErrorDocument 417 /index.php?error=417
ErrorDocument 418 /index.php?error=418
ErrorDocument 419 /index.php?error=419
ErrorDocument 420 /index.php?error=420
ErrorDocument 421 /index.php?error=421
ErrorDocument 422 /index.php?error=422
ErrorDocument 423 /index.php?error=423
ErrorDocument 424 /index.php?error=424
ErrorDocument 425 /index.php?error=425
ErrorDocument 426 /index.php?error=426
ErrorDocument 500 /error/503/index.html
ErrorDocument 501 /index.php?error=501
ErrorDocument 502 /index.php?error=502
ErrorDocument 503 /error/503/index.html
ErrorDocument 504 /index.php?error=504
ErrorDocument 505 /index.php?error=505
ErrorDocument 506 /index.php?error=506
ErrorDocument 507 /index.php?error=507
ErrorDocument 508 /index.php?error=508
ErrorDocument 509 /index.php?error=509
ErrorDocument 510 /index.php?error=510

错误文件常见问题

为什么不直接硬编码所有指向404.php文件的路径?

通过index.php调用错误文件,以此确保我们更改主题时,所用的404.php文件也能自动发生变化。

换用一个没有404.php文件的主题时会出现什么情况?

这时点击了断链的访问者会看到网站主页的副本(index.php),但他们看到的URL仍然是断链的URL。这会使访问者产生疑惑,尤其是网站并没有给出错误提示。但即使这样,也比让访问者只看到“Not Found”页面而不提供其它任何有价值的信息或链接要好的多。

其它错误码

除404错误码外,还有很多标准web错误码。Apache Status Codes and ErrorDocuments中介绍了这些错误码的信息头和输出结果。

  • 100 继续
  • 101 切换协议
  • 102 处理中
  • 200 确定
  • 201 已创建
  • 202 已接受
  • 203 非权威性信息
  • 204 无内容
  • 205 重置内容
  • 206 部分内容
  • 207 多状态
  • 300 多选择
  • 301 永久重定向
  • 302 已找到
  • 303 参见其它
  • 304 未修改
  • 305 使用代理
  • 307 临时重定向
  • 400 错误请求
  • 401 要求授权
  • 402 要求付款
  • 403 禁止访问
  • 404 未找到
  • 405 用来访问本页面的HTTP谓词不被允许(方法不被允许)
  • 406 客户端浏览器不接受所请求页面的MIME类型
  • 407 要求进行代理身份验证
  • 408 请求超时
  • 409 矛盾
  • 410 消失
  • 411 要求长度
  • 412 前提条件失败
  • 413 请求实体太大
  • 414 请求URI太长
  • 415 不支持的媒体类型
  • 416 所请求的范围无法满足
  • 417 执行失败
  • 422 实体无法执行
  • 423 锁定的错误
  • 424 依赖项无效
  • 425 无代码
  • 426 要求升级
  • 500 内部服务器出错
  • 501 页眉值指定了未实现的配置
  • 502 Web服务器用作网关或代理服务器时收到了无效响应
  • 503 服务暂时不可用
  • 504 网关超时
  • 505 HTTP版本不受支持
  • 506 商定变量
  • 507 内存不足
  • 510 无法扩展
#1
太麻烦……至少需要花半小时来搞……VEN帮我完成了吧……
#2
又在你的博客里面找到了好东西,你的域名好强大啊