本文于2015年底完成,发布在个人博客网站上。 考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来。
背景
某一天在办公室分析产品首页加载速度时,无意中从Chrome浏览器的调试窗口看到浏览器在请求一个名为favicon.ico
文件,由于Web系统的根路径下不存在这个文件,Chrome仅报了404
访问失败,但当时没有太关注。
直到后来在某一次版本上线结束后的下午,还是在分析产品首页的加载速度,突然发现浏览器加载favicon.ico
文件时,Web服务器居然把整个首页重新返回了一次,拖累了首页的加载速度。
如是,摆在眼前有两个问题:
favicon.ico
是何方神圣,为什么浏览器会要求加载这个文件?IE11
加载favicon.ico
文件失败后,居然再次下发加载首页的请求,导致首页加载了两次?
为什么浏览器要访问favicon.ico?
favicon.ico是什么
从百度百科中,可以找到如下描述:
favicon.ico图标是网站的缩略标志,可以显示在浏览器标签、地址栏左边和收藏夹,是展示网站个性的缩略logo标志,也可以说是网站头像,如果要让网站看起来更专业、更美、更有个性,favicon.ico是必不可少的。
浏览器调用favicon的原理是首先在网页所在目录寻找favicon.ico文件,如果没有找到就去网站的根目录寻找。所以最简单的方法就是将制作好的favicon文件命名为favicon.ico然后上传到网站的根目录下。
从资料可以得出解决本问题的方法。
解决方法
在首页的<head>
增加如下的代码:
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
这时清理浏览器缓存,并强制浏览器不缓存数据,多次刷新页面,观察浏览器控制台监控到的HTTP请求,发现浏览器可以成功获取favicon.ico
。Web服务器按照预想返回了图片,而不是首页页面。
这样就成功的消除了一次多余的页面返回动作。
没想明白的怪事
不过有件事情没有想明白。我使用WordPress 4.1在SAE上搭建的博客网站,在网站根目录下没有找到favicon.ico
,但使用前述的测试手段来做验证时,居然没有观察到浏览器要求下载favicon.ico
的请求。
为什么?
IE11
加载favicon.ico
文件失败后,为什么会再次下发加载首页的请求?
其实问题还有一个,为什么之前分析页面加载过程的时候,没有观察到首页被加载两次的现象。
使用IE11
的调试工具仔细观察首页的刷新过程,发现其实不只是在访问favicon.ico
失败时服务器返回首页,IE11
在访问jquery.min.map
文件失败时,服务器也会返回首页。
jquery.min.map
又是什么鬼?
查阅jquery
的官方资料,原来这是jquery 1.9
版本的新特性。通常情况下,为了降低浏览器下载js文件的时延,我们在Web系统的生产环境里只会部署压缩版本的jquery.js
。这没有什么问题,而且通常情况下都很好,但凡事总有例外。当客户投诉页面访问时出现js报错,而我们本地又无法重现问题,只好直接用浏览器来调试生产环境,问题就来了。压缩版本的jquery
里,变量名、代码全部缩在一起,查看非常不方便,理解很困难。source maps
就是解决这个问题的利器。jquery 1.9
发布比较早,彼时只有Chrome
支持source maps
;现在已过去好多年,从IE11
的表现看,应当也已实现了source maps
的支持。
虽然知道了jquery.min.map
是什么鬼,但对于定位问题本身并没有什么帮助。因为我还是不知道如何观察浏览器的行为。
分析问题的笨方法
最初想了很久不知如何下手,后来想代码里引用到首页的地方应该不多,干脆在相关的地方全打上断点,调试一下看看,说不定会有所发现。于是在代码里全局搜索首页的文件名,找出引用到首页的几处代码,在相关的Java代码中打上了断点。这时启动容器,用浏览器登录首页,打开浏览器的调试器,刷新页面,监控Java代码。
在几处正常的访问点上,代码表现正常,但在处理favicon.ico
的下载请求时,服务器返回了重定向的消息。我精神一振,预感神秘的问题快要找到原因了。仔细查阅重定向操作相关的代码,外加几次调试,终于搞清楚了问题所在。原来系统的代码实现了对URL的访问控制,限定浏览器只能访问以.css
、.js
、.png
、.jsp
、.action
为结尾URL,浏览器对其它形式URL的访问均会被重定向到首页。
代码分析到这里,问题就清楚了。
问题原因
favicon.ico
和jquery.min.map
文件的结尾不在前述文件后缀范围之内,于是加载这两个文件的请求被服务器的代码重定向回了首页,因而IE11
按照服务器的要求重新加载了首页。- 之前调试代码的时候,我并没有设置禁止
IE11
访问缓存;因此当IE11
被服务器代码要求重新加载首页时,IE11
发现首页已加载过,于是直接使用了缓存中的页面,这样我自然看不到第二次加载首页的请求了。
问题清楚了,解决的手段自然就有了。
解决方法
- 找项目组的美工MM,参照产品的Logo制作了一个16*16的
favicon.ico
文件,上传到的WebRoot的根路径,这下favicon.ico
文件就有了。 - 修正代码,调整权限控制的部分,把
.ico
和.min.map
加入到免认证的列表里,避免浏览器访问这两类文件时被重定义向。这个问题的发生,完美的诠释了我同事的口头禅,诡异的问题通常都是愚蠢的错误引入的。
参考资料
在网上搜索到一些材料,对于问题的定位起到了很大的作用,这里记录下来。