百度空间 | 百度首页 
 
查看文章
 
如何解决头像更新后看不到变化的问题
2008-11-06 00:17
以前在使用鲜果修改个人资料的时候,就遇到这样一个问题:更新自己的头像以后,看到的头像却还是和原来一样。对于开发人员来说,很容易就会想到,这是这个头像对应的文件已经在浏览器端进行了缓存,没有重新向服务器请求,所以会导致更新头像后依然看不到任何变化的情况出现。这时候,只要按一下F5或者浏览器的“刷新”按钮,浏览器就会把最新的头像显示出来。也就是说,浏览器重新向服务器请求了一次这个头像对应的文件。不过,这样的事情要让一个普通用户来理解,还是有相当的困难的,而且,让他们不能通过页面的点击就完成自己所需要实现的动机,而是要增加额外的动作来作为辅助手段,往往会带来心理上的不愉悦感。所以,问题还是要开发人员来解决的。

我先查看了两个比较典型的照片类站点——flickr又拍。虽然又拍在很大程度上是copy的flickr,不过在头像的修改上机制还是不一样的。

flickr 在没有修改头像之前我的头像地址是:http://farm3.static.flickr.com/2283/buddyicons/15633695@N07.jpg?1225208994#15633695@N07;在修改过后,头像地址变成了:http://farm3.static.flickr.com/2283/buddyicons/15633695@N07.jpg?1225893477#15633695@N07。从两个地址不一样的地方出发,发现在问号以后的参数发生了变化,基本上应该是一个反映图片最后修改日期的时间戳。由此可见,flickr对于头像的修改是通过在地址中加入最后修改日期时间戳来保证用户看到的头像是最新的那一个。换句话说,flickr实际上并没有对浏览器端缓存的文件进行任何处理,而只是通过地址后面的cgi参数保证浏览器显示最新的头像文件。

又拍 同样,对比修改头像前后头像的地址,发现修改前的地址为:http://ico.yupoo.com/comdeng/99262675157c/,修改后则变成了:http://ico.yupoo.com/comdeng/99262675157c/。可以看到,用户每次修改头像都会生成一个新的文件,产生了一个新的url,这就从根本上绕开了浏览器的缓存机制,彻底保证了头像一更新用户就能看到新的头像。

对比一下两者的处理方式:
1、flickr避开原始头像的缓存是对地址后面的cgi参数进行了变更,在服务器端的文件数量没有增加,直接替换了原来的;而又拍则是把头像的地址换成了一个新的,在服务器端增加了一个新的头像文件,而原来的头像通过对应的地址还是可以访问得到。虽然一个头像文件不算太大,但又拍的做法无疑给服务器增加了一些琐碎的无用文件,不是一种高明的做法。

2、flickr的处理方式每次显示头像都需要携带一个含有时间戳的cgi参数,看那个地址就感觉不太优雅。显然,这个参数需要用数据库等存储起来(或者直接通过文件属性获取?)。又拍的也同样需要在数据库里边配置字段来保存头像的地址。为了一个区区的几百个像素的头像,还要在数据库开辟专门的字段来标识其地址,感觉很不划算。

既然这两个网站的方式都不太理想,那么我就自己来动身解决一下吧。

第一种 用户上传以后,显示图片的时候像flickr一样,将头像地址后面加入包含时间戳的cgi参数。这样,用户马上就能看到修改后的头像。不过,当用户换到别的没有cgi参数的头像页面,则又看到了浏览器端缓存的旧头像。依然没有解决问题,失败!

在修改头像以后,利用浏览器本身的刷新功能,能使头像重新加载一遍,从而使用户看到最新的头像。那么,是不是我们可以从这一点出发,利用html语言或者js来模拟一下这种刷新,从而代替用户的手动操作呢?因此,出现了我考虑的第二种方案。

第二种 用户上传以后,显示图片的时候,加上cgi参数,然后让整个页面刷新一次。再回到显示没有cgi参数头像的页面,发现这个图片果然没有被缓存住了。 这里所谓刷新,就是通过html里边head里边表示这样的代码:<meta http-equiv="refresh" content="0"/>这种方式不需要浏览器端有对js的支持,可以说还比较完美。如何保证页面只刷新一次呢?对于http这种无状态的协议方式来说,通过cookie来保存访问次数是比较合理的。不过,似乎这种方式需要检查各个浏览器的兼容性。在firefox3 和ie7上测试,都顺利通过了。不过,跑到我机器上剩下的另一个浏览器——chrome,却神奇般的没有实现想要的结果。虽然直接在chrome里边刷新页面能让浏览器缓存的文件被替换掉,但是通过meta的refresh却还是不能让chrome实现同样的效果。没办法,依然失败!

最后,突然想起在百度修改头像的时候似乎也解决了头像修改的问题,于是,迫不及待地跑了过来。经过初步地侦查,发现百度是把头像放在一个iframe里边,因此,马上想到通过iframe里边的重载来实现模拟浏览器的刷新效果。
上图中标红的地方就是一个iframe,其src为http://hi.baidu.com/sys/personal/view/4016636f6d64656e679d01,就是防止了url为http://himg.baidu.com/sys/portrait/item/4016636f6d64656e679d01.jpg的头像,浮动层里边的图像地址是http://himg.baidu.com/sys/portrait/item/4016636f6d64656e679d01.jpg?t=1225902339620,加入了时间戳作为cgi参数,保证用户上传时看到的图片是最新版本的。当上传一个新的图片完毕后,调用js使得iframe里边的页面重新加载一次,充当了模拟浏览器刷新功能,使得浏览器重新发起一次对头像文件的请求,从而实现更新本地浏览器缓存的目的。

有了思路,接下来就行动了。基本页面如下:
iframe1的url为face.php?actorId=1,face.php仅仅是用来显示actorId=1的用户的头像。位置为:/static/picture/people/1.jpg,不用加任何cgi参数。iframe2是用来实现图像的上传的框架。设置iframe2的name为frmUpload,并把上传控件所在form的target设为frmUpload,那么点击修改时的上传操作就会在iframe2里边进行,从而实现不用刷新整个页面进行图片上传的操作。给iframe2增加onload事件,当上传图片完毕时就会引起这个事件,此时,对iframe1的location进行reload操作,就会加载出最新的头像文件来。

主要的代码如下:
<script type="text/javascript">
        //上传完毕时调用该函数
        function onUploadOver() {
            var c = document.getElementById('frmUpload').contentWindow.document.body.innerHTML;
            if (c == "1") { //modifyface.php里边上传文件成功时写下“1” 因为当页面初始化时frmUpload也会引起onload事件,但body里边是空白的,什么也没有,因此可以这样来区分两种载入事件
                frames["frmFace"].location.reload(); //重新加载frmFace里边的页面,使得浏览器发出对头像文件的重新请求,获取到最新的头像
                $('#uploadPicture').val('');
            }
        }
    </script>
<!--form的target指向frmUpload,表单提交时会在frmUpload里边进行处理-->
    <form enctype="multipart/form-data" method="post" action="/modifyface.php" target="frmUpload">
    <input type="hidden" name="MAX_FILE_SIZE" value="2000000"/>
    <table cellspacing="4" cellpadding="0" border="0" width="100%">
        <tr>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td class="r">头像:</td>
            <td><input type="file" name="picture" id="uploadPicture" size="40"/><span class="g">不超过2M</span></td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit" value="修改" id="btnUpload"/></td>
        </tr>
    </table>
    </form>
<!--这个iframe用来实现无刷新上传,处理完毕会引起onload事件-->
    <iframe id="frmUpload" name="frmUpload" frameborder="0" scrolling="no" style="width:0px;height:0px;" onload="onUploadOver()"></iframe>
至此,头像更新后看不到变化的问题基本得到解决,并且通过了firefox3、ie7和chrome0.3三种浏览器的测试。最后,总结如下:
一、这种方法是利用对iframe里边的location进行reload操作,模拟浏览器的刷新功能,使得浏览器对已经缓存过的文件发出一次新的请求,从而获取到最新版本的图片文件。
可能对别的文件,比如css样式表和javascript文件,这样的操作也是有效的,需要进一步测试。
二、这种方法不需要在服务器端增加新的文件,而且也不需要带有时间戳等cgi参数在url后边,只需要有浏览器端javascript的支持即可完成。比flickr和又拍的处理方法要技高一筹。

类别:技术追峰 | 添加到搜藏 | 浏览() | 评论 (2)
 
最近读者:
 
网友评论:
1
2008-11-06 16:45 | 回复
有没有考虑过,自己访问自己的图像时的地址是不一样的 这种方式
 
2
2008-11-06 17:52 | 回复
这倒也可以,反正别人对于头像是否更新过并不关注。不过,如果用到头像的地方比较多,每次一到显示自己头像的时候就需要做些多余的判断,也还是不太爽。
 
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu