HTTP 404 错误意味着链接指向的网页不存在。在网站建设中想要完全避免这种情况是不可能的,比如说,我们常常需要对网站进行调整、改版,便会有网页被删除、改名或移动位置,这时候,虽然相应内容的网页还存在于网站中,但使用原来的地址访问则无法访问。——当然,对这类情况首先要考虑的是为原来页面地址做301重定向,以尽可能地减小对SEO效果的影响。——其次,在别人建立指向网站的链接时,也可能会由于出现拼写错误而使其成为一个无效的链接:在网站内找不到相应的内容页面。
简单说来,这类无效链接是由web服务器自动处理的:当Web 服务器接到类似的数据请求量,会返回一个 404 状态码,告诉对方其要请求的资源并不存在。但是,Web服务器默认的404错误页面,无论Apache还是IIS,均十分简陋、呆板且对用户不友好,无法给予用户寻找相应信息的更多线索,用户看到这类页面往往最直接的反应并是关闭浏览器窗口离开,这在很大程度上给网站造成损失。毕竟,对网站来说,用户永远是最重要的资源,以这种方式损失用户更意味着某种程度的失败。
这也是许多网站使用自定义404错误页面的原因。通过良好的自定义404页面,可以包含对网站的相应介绍、用户可能感兴趣的内容链接或者网站内容导航链接、内容搜索功能等,能够有效地帮助访问者找到其欲寻找的内容或相似的内容,提高用户在网站内浏览更多信息的机会。
自定义404错误页面返回“200”或“302”状态码
从严格的技术角度,网站对404错误的处理策略,并不是一个SEO方面的工作,而属于网站可用性(usability)方面的问题。——当然,如果从广义的SEO范畴来看,提高网站可用性也属于SEO的基本操作。——但是,如果自定义404错误页面设置不当,则会极大地影响网站的SEO效果。
在许多朋友的印象中,自定义404错误页面只要能正确显示,只要能输入网站内某个并不存在的网页地址,在浏览器中能看到自定义的错误信息,便说明设置没问题。惭愧地说,本人也是抱有这种想法的一员,IT技术点评运行将近一年了,近日因Google更新后排名下降检查网站时才发现存在类似的错误:一个正确设置的404页面,不仅应当正确地显示,同时,应该能够正确返回“404”错误代码,而不是“200”或“302”。虽然对访问的用户而言,HTTP状态码究竟是“404”还是“200”来说并没有什么区别,但对搜索引擎而言,这则是相当重要的。
为什么这么说呢?让我们先来回顾一下搜索引擎收录与索引网页的过程:搜索引擎的Spider向网站服务器发送请求,要求读取某个网页,网站服务器接到请求后返回 HTTP 状态码响应请求,这些返回的HTTP状态码决定着搜索引擎的下一步行动:将该网页收录到索引数据库或者将其从索引数据库删除等。
当然,HTTP状态码有很多种,分别对应不同的情况,下面就与本文内容相关的几种作一简单介绍,更详细的信息可参考W3C规范:
404 : 请求的网页不存在(不排除日后该链接有效的可能性);
410 : 请求的网页不存在(永久);
200 : 服务器成功返回网页
302 : 网址临时重定向(跳转)
301 : 网址永久重定向
需要说明的是,大部分搜索引擎将“404”与“410”状态同等对待,如Google。(参见Matt Cutts的说明)
当搜索引擎在请求某个Url时得到“404”状态回应时,便会知道该网页在网站内不复存在,从而在索引数据库中将其删除,——当然,这个删除过程有可能需要很长时间——而当搜索引擎得到“200”状态回应时,则会认为该url是有效的,并将其回到到索引数据库中。
404页面返回“200”状态码的后果
如果网站的自定义404错误页面在url无效时不返回“404”状态码而代之以“200”,会发生什么情况呢?很明显,搜索引擎会认为这个“根本不存在的”网页在网站内是存在的,这会导致很多问题,影响网站的最终SEO效果。
举例来说,比如说对“http://www.highdiy.com/a.html”、“http://www.highdiy.com/b.html”这两个在IT技术点评网站内并不存在的url而言,如果搜索引擎得到的回应状态码是“200”,那么,便会将其收录到索引数据库,这样的结果便是这两个不同的url具有完全相同的内容:自定义404错误页面的内容,这类重复文本(Duplicate Content)的现象对许多搜索引擎而言都是大忌。尤其是考虑到网站中不可能只有这两个无效链接,毕竟在网站建设中,无论网站的内部链接还是外部链接,总会不可避免地出现许多比如说拼写错误的情况,类似的重复内容会更多。这样,对搜索引擎而言,特别是Google,不但很难获得理想的网站信任指数,也会大大降低Google对网站质量的评定。
404错误页使用Meta Refresh带来的302问题
常常看到许多网站的自定义404错误页面采取类似这样的形式:首先显示一段错误信息,然后,通过Meta Refresh将页面跳转到网站首页、网页地图或其他类似页。根据具体实现方式不同,这类404页面可能返回“200”状态码,也可能返回“302”,但不论哪种,从SEO的角度看,均不是一种合适的选择。
对“200”状态的情况我们上面已经谈过,那么,当404页面返回“302”时,搜索引擎会怎么对待呢?从理论上说,对“302”错误,搜索引擎认为该网页是存在的,只不过临时改变了地址,仍然会索引收录该页,这样,同样会出现类似于“200”状态码时的重复文本问题;其次,以google为代表的主流搜索引擎对302重定向的适用范围要求越来越严格,这类不当使用302重定向的情况存在很大的风险。
因此,尽量不要在404错误页中使用这类Meta Refresh方法。如果实现希望实现类似的功能,即让显示错误信息几(十)秒后跳转到首页或其他页面,可以考虑在404错误页中使用Java Script跳转。——Java Script对搜索引擎而言是无益同时也无害的。
确保自定义404错误页面能够返回“404”状态码
在自定义404错误页面设置完毕后,一定要检查一下其是不是能够正确地返回“404”状态码。
检查的方法也相当简单,使用本站提供的Server Header检查工具,或其他类似工具如这个,输入一个网站内不存在网页的url,查看一下HTTP Header的返回情况,确信其返回的是“404 Not found”。
本文针对Apache + PHP的网站,如果是Win的,思路也差不多。自定义404页面,也就是当用户访问一个不存在的页面时不显示服务器默认的错误页面,而是显示一个事先做好的提示页面,用户浏览器地址栏的网址依然是他输入/访问的网址。这样做至少有两个好处:
- 让用户感到这个错误依然在网站的控制范围内,“这是演出的一部分”。
- 让webmaster即时知道有这么一个404页面。
先说说产生404的几种可能
- User-Agent(浏览器、搜索引擎bots)会访问固定的文件,例如Maxthon/Firefox浏览器会请求所有被访问网站的favicon.ico,如果恰巧那个网站没有这个ico文件,它的服务器log就会多出一行404错误提示,同样的还有搜索引擎请求robots.txt文件。
- 用户错误的输入了URL。比如某人先前访问网站的页面/page1.html,然后利用浏览器地址栏的记录功能重新访问,不料错把backspace当成了回车,意识到后又因为手比脑快直接按回车访问了/page1.htm页面(少了个l)。
- 某个页面被删除了,而其他网站,如论坛、搜索引擎还在引用这个链接。
对于第一种情况,当然是上传favicon.ico和robots.txt文件到根目录,制作方法和书写规则不再多说。对于第二种情况,所能做的就是和第三种情况进行区分,既只有因第三种情况发生的时候才通知webmaster进行处理。
下面是Apache + PHP制作自定义404页面的方法。
首先处理文件真的不存在的情况,方法是利用Apache的.htaccess定义,网上介绍的文章很多,不再敷述,方法是在.htaccess最开头加上:ErrorDocument 404 /404.php (/404.php是自定义404页面)。
其次要处理另一种更为常见的404,即数据不存在的404。比如这个Blog系统是数据库驱动的,当用户访问某篇文章时Blog程序会根据ID查询数据库,如果恰好这个文章被删除,则应该告诉用户该页不存在,同样的情况还适合于论坛删贴后的提示。目前多数Blog和论坛,及其它数据驱动的网站,处理这种问题的做法是仅显示不存在的提示而不发送404 header,或者干脆转向到/404.php页面(这样浏览器的地址栏就变成了/404.php)。这种做法的缺点是搜索引擎会看到该网站有很多内容相同(都是不存在的提示文字),URL不同的页面,或者是看到该网站有很多通过302转向到同一个页面的情况,这些都有可能被搜索引擎误以为是SPAM而惩罚该网站(很多被惩罚的网站始终认为自己是无辜的,其实都是小错积累的结果)。因为已经pass过了服务器层,.htaccess的404定义不再起作用,所以在读取数据的php文件种针对这种情况应该做以下处理:
<?
$id = $_GET['id']; //这里获得文章、帖子的索引id
//通过 $id 查询数据库
if(如果没有任何结果)
{
//以前是仅仅显示“该帖子已经不存在”的提示,现在是:
require('/404.php');
@header('HTTP/1.1 404 Not Found');
@header('Status: 404 Not Found');
exit;
}
?>
这样做可以保证显示404.php的内容,并且发送404 header,并且浏览器地址栏的网址依然是那个用户原始访问的网址。从人类理解的角度往往会把header()语句放在require()上面,但那会使php停止执行下面的require函数,把header放在最后反而能把404 header发送出来。建议编写论坛、博客和数据驱动网站程序的人都用上面的方法处理数据不存在时的提示信息,避免和搜索引擎产生误会。
最后说说前面提到的通知webmaster的问题,即区分产生404的第二、第三种情况。显然,两种情况的区别是情况二不含有REFERER信息,所以通知webmaster的代码应该是这样的:
<?
...
if($_SERVER['HTTP_REFERER'] != '') //如果有referer,则证明来自某个页面的点击
{
mail(...把404页面 $_SERVER['REQUEST_URI']和referer页面$_SERVER['HTTP_REFERER']通过email寄到webmaster的信箱);
}
?>
这样webmaster在收到email后应即时联系$_SERVER['HTTP_REFERER']网站的webmaster修改链接。如果$_SERVER['HTTP_REFERER']是搜索引擎,则因为自定义404页面发送了404 header,搜索引擎会在下次更新索引的时候删除这个页面。如果实在不放心,可以在/404.php页面的头部加上meta tag拒绝所有bot:
<meta content="NOINDEX, NOFOLLOW" name="ROBOTS" />
这样就万无一失了。
5秒后!!!自动跳转到站点首页!
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>无法找到该页</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=GB2312">
<STYLE type="text/css">
BODY { font: 9pt/12pt 宋体 }
H1 { font: 12pt/15pt 宋体 }
H2 { font: 9pt/12pt 宋体 }
A:link { color: red }
A:visited { color: maroon }
#goto{ color:#FF0000; font-size:30px; font-weight:bold}
</STYLE>
<script type="text/JavaScript">
function out(obj){
var i=obj;
if(i==0)
document.location.href="http://www.p2psun.cn";
document.getElementById("goto").innerHTML=i;
i--;
setTimeout("out("+i+")",1000);
}
</script>
</HEAD><BODY onLoad="out(5);"><TABLE width=500 border=0 cellspacing=10><TR><TD>
<h1>无法找到该页</h1>
您正在搜索的页面可能已经删除、更名或暂时不可用。
<div><span id="goto"></span>秒后转入主页,或者你可以直接点击进入<a href="http://www.p2psun.cn">http://www.p2psun.cn</a></div>
<hr>
<p>请尝试以下操作:</p>
<ul>
<li>确保浏览器的地址栏中显示的网站地址的拼写和格式正确无误。</li>
<li>如果通过单击链接而到达了该网页,请与网站管理员联系,通知他们该链接的格式不正确。
</li>
<li>单击<a href="javascript:history.back(1)">后退</a>按钮尝试另一个链接。</li>
</ul>
<h2>HTTP 错误 404 - 文件或目录未找到。<br>Internet 信息服务 (IIS)</h2>
<hr>
<p>技术信息(为技术支持人员提供)</p>
<ul>
<li>转到 <a href="http://go.microsoft.com/fwlink/?linkid=8180">Microsoft 产品支持服务</a>并搜索包括“HTTP”和“404”的标题。</li>
<li>打开“IIS 帮助”(可在 IIS 管理器 (inetmgr) 中访问),然后搜索标题为“网站设置”、“常规管理任务”和“关于自定义错误消息”的主题。</li>
</ul>
</TD></TR></TABLE></BODY></HTML>