解决IE下自定义HTTP错误页太小不显示并导致显示默认友好错误页问题
提醒:本页面将不再更新、维护或者支持,文章、评论所叙述内容存在时效性,涉及技术细节或者软件使用方面不保证能够完全有效可操作,请谨慎参考!
今天研究起WordPress的评论发布页 wp-comments-post.php ,假如我们提交一个不是期望的评论,比如我们什么都不写就点击提交评论,然后WordPress将交由 wp-comments-post.php 处理,当然这次处理将以失败告终,WordPress将显示一条错误消息,比如:“错误:请填写必填项目(姓名和电子邮件地址)。”。好了,这时如果我们右击查看源代码会找到一段奇怪的字符串:
<!-- Ticket #11289, IE bug fix: always pad the error page with enough characters such that it is greater than 512 bytes, even after gzip compression abcdefghijklmnopqrstuvwxyz1234567890aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuu vvwwxxyyzz11223344556677889900abacbcbdcdcededfefegfgfhghgihihjijikjkjlklkmlmln mnmononpopoqpqprqrqsrsrtstsubcbcdcdedefefgfabcadefbghicjkldmnoepqrfstugvwxhyz 1i234j567k890laabmbccnddeoeffpgghqhiirjjksklltmmnunoovppqwqrrxsstytuuzvvw0wxx 1yyz2z113223434455666777889890091abc2def3ghi4jkl5mno6pqr7stu8vwx9yz11aab2bcc3 dd4ee5ff6gg7hh8ii9j0jk1kl2lmm3nnoo4p5pq6qrr7ss8tt9uuvv0wwx1x2yyzz13aba4cbcb5 dcdc6dedfef8egf9gfh0ghg1ihi2hji3jik4jkj5lkl6kml7mln8mnm9ono -->
看似杂乱无章的字符串,有什么实际作用呢?好在我看到了这么一句话 Ticket #11289, IE bug fix: always pad the error page with enough characters such that it is greater than 512 bytes, even after gzip compression ,貌似和IE什么Bug有关系,立即Google之,找到了WordPress原先的Bug处理页 《Internet Explorer, 512-byte error page fix doesn't work. Neglects gzip compression.》 。
通过上述描述得知当自定义HTTP错误页(Custom HTTP Error Page)体积过小,小于一个临界阈值(thresholds)时,IE浏览器将自动以内部错误页面(Microsoft-stylin' error page)来取代你的自定义错误页。
什么意思呢?首先我们要理解什么是自定义HTTP错误页。当然要理解HTTP状态码(HTTP Status Code),比如说我们找不到页面时服务器将返回一个404状态码,表示找不到页面,当我们进行301或者302重定向时也是通过这个状态码来进行,当然还要有一些附加信息,比如状态,这些信息是写到HTTP相应头(HTTP Response Header)里的,只有浏览器等客户端可以“看到”并理解这些信息,然后翻译传达给我们,这里给个找不到页面的status header:
HTTP/1.1 404 Not Found Server: nginx Date: Mon, 05 Mar 2012 08:20:41 GMT Content-Type: text/html Content-Length: 564 Connection: keep-alive Keep-Alive: timeout=5
其中 HTTP/1.1 404 Not Found 这个就是我们要关注的,HTTP表示协议,1.1表示版本,404表示状态码,Not Found表示状态,那么这个Header等于告诉浏览器找不到页面,我刚才说了这个是由服务器发送的,当然也是我故意访问了一个不存在的页面,服务器才发送这个404消息,学过任何一种Web编程语言的同学知道,其实这个也是可以自定义的,比如在PHP中,我们这样写可以实现同样的功能,即使这个页面是存在的:
<?php header("HTTP/1.1 404 Not Found"); ?>
好了,这里我为了便于演示,换一种状态代码500,表示服务器错误:
<?php header('HTTP/1.1 500 Internal Server Error'); ?>
现在访问这个页面表明我们自定义了一个500内部服务器错误的HTTP错误页,而且浏览器等客户端也可以理解这种错误页,当然我们需要提供一些其他信息来告知我们的访问者,当前页面出错了:
<?php header('HTTP/1.1 500 Internal Server Error'); ?>
<html>
<head>
<title>Error</title>
</head>
<body bgcolor="white">
<center><h1>当前页面出错咯</h1></center>
</body>
</html>
小提示:header必须在任何HTML或者文本输出前发送,否则无效。
好啦,把上面的代码写入到500.php文件里并上传服务器,然后再通过浏览器浏览,Chrome下显示正常为“当前页面出错咯”我们设定的文本,IE下却显示其内部内置的“HTTP 500 内部服务器错误,无法显示网页,您要访问的网页有问题,无法显示。”,如下图所示:
这个页面很熟悉?是的,搞ASP开发的同学肯定有印象,而且需要修改“Internet 选项”,高级选项卡,去掉“显示友好 HTTP 错误信息”的钩才能将我们自定义的错误文本显示出来。
让我们的客户去改浏览器设置?呵呵,这当然是不现实的,可能有同学要问:为什么有些网站的自定义HTTP错误的自定义文本能够正常显示,比如一些站漂亮的404页面。说了这么多,这个就是我们今天要研究的问题。
让我们回到本文一开始那个IE Bug,其实这个Bug也反映了这个问题,当服务器响应的内容长度小于一定的临界阈值(thresholds)时,IE浏览器将自动忽略服务器在响应头发送完后的自定义文本,也就是我们设定的文字被IE忽略了,取而代之的是IE自家的内部错误页面(Microsoft-stylin' error page)。我们看下刚才那个页面的size:
对于500错误的阈值IE默认设置为512 bytes(更多的阈值稍后介绍),很明显刚才我们构造的页面不足512 bytes,所以IE没有显示我们的页面,好了,大家肯定在想,如果大于这个阈值(thresholds),那么我们的页面不就能够正常显示了?恭喜你,回答正确!比如我们将页面人为的填充垃圾值,使其大于512字节,当然为了不影响整体页面,我们将其放入到HTML注释中:
<?php header('HTTP/1.1 500 Internal Server Error'); ?>
<html>
<head>
<title>Error</title>
</head>
<body bgcolor="white">
<center><h1>当前页面出错咯</h1></center>
<!-- <?php echo str_repeat('*', 256); ?> -->
</body>
</html>
很明显现在页面size大于512这个阈值了,假如我们现在用IE访问这个页面,即使不关闭显示友好 HTTP 错误信息,也会显示我们自己的消息文本了。
当然这里需要注意的还有Gzip,如果说这里页面本来就大于512个字节,但是gzip压缩输出后页面却小于了512个字节,那么IE依旧会用自己的错误页取代我们的错误也,所以这里填充的垃圾值要考虑到这个问题,由于压缩的特性,重复字符压缩效率高,我们为了扩充体积不希望看到这个效果,所以需要使用不重复的乱字符填充,恐怕这也是为什么一开始WP的杂乱字符填充的原因吧。
竟然这个阈值有这样神奇的效果,那我们如何获取不同错误页面的IE默认临界阈值呢?下面列出一张表供大家参考:
代码 | 描述 | 文件大小(阈值) |
---|---|---|
400 | Bad Request | > 512 bytes |
403 | Forbidden | > 256 bytes |
404 | Not Found | > 512 bytes |
405 | Method Not Allowed | > 256 bytes |
406 | Not Acceptable | > 512 bytes |
408 | Request Time-out | > 512 bytes |
409 | Conflict | > 512 bytes |
410 | Gone | > 256 bytes |
500 | Internal Server Error | > 512 bytes |
501 | Not Implemented | > 512 bytes |
505 | HTTP Version Not Supported | > 512 bytes |
当然上面那张表不是空穴来风,是根据IE配置来的,这个配置保存在注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main\ErrorThresholds ,你可以根据需要编辑修改这个值:
刚才看到Nginx的默认错误页,比如404错误,也应用了相应的技巧来避免这个问题:
<!-- a padding to disable MSIE and Chrome friendly error page --> <!-- a padding to disable MSIE and Chrome friendly error page --> <!-- a padding to disable MSIE and Chrome friendly error page --> <!-- a padding to disable MSIE and Chrome friendly error page --> <!-- a padding to disable MSIE and Chrome friendly error page --> <!-- a padding to disable MSIE and Chrome friendly error page -->
不过看字面意思,貌似Chrome也有这种特性?而且试了一下,貌似只有IE或者Chrome访问才会有这么几行HTML注释Padding。
另外某些浏览器外壳,可能会捕获相应的HTTP错误头,以便于显示其内置的页面,如果这样的话,这里的技巧就不起作用了,还是建议大家使用主流浏览器。
参考文档
这个问题我也遇到过,就是说如果IIS自定义404或者500等页面的大小过小,就不会跳转到自定义的错误提示页面。呵呵~换其他浏览器就没问题。
恩,IE的特例多,比如像网页设计的hasLayout特性,都是其独有的,有时还是给我们带来一定的麻烦。