可即时更新的静态文件客户端缓存

书弋江山 2013-01-25

转自http://blog.csdn.net/zandershi/article/details/2989131

在Web网站中,css/js/image等静态文件不仅占用大量的网络带宽,而且给服务器端的CPU和IO系统带来极大的负载,是影响服务器吞吐量的重要因素。要解决这个问题,一个有效办法是在客户端对静态文件进行缓存。缓存有可能会导致静态文件不能在客户端即时更新,而某些网站恰恰需要客户端的js/css等缓存文件必须即时更新,否则会对用户体验带来影响。在Web2.0时代,这更是一个不容忽视的问题。

那么,怎么样才能实现即减少网络流量和服务器负载,又能在必要时即时更新客户端缓存的目的呢?

启用客户端缓存

在HTTP/1.0的年代,可以通过设置HTTP头中的Expires字段来告诉浏览器缓存的有效时间。但这个时间是在服务器端生成,在客户端检验,因此如果服务器和客户端的时间不同步,那就有可能产生问题。此外,在有效时间截止之前,浏览器会直接使用本地缓存内容,不会与服务器沟通以检测文件是否更新,因此会导致更新不即时的情况。

HTTP/1.1协议引入了Cache-Control这个新的HTTP头字段,以浏览器访问服务器时的时间为基准,用相对于这个基准的时间来作为缓存应该失效的时间,这就解决了服务器和客户端时间不同步有可能产生的问题。在缓存失效后,

缓存失效后的文件内容验证

一旦设定的缓存失效时间已到,那么浏览器就需要向服务器发出请求,来验证服务器端的内容是否确实做了修改。

在HTTP/1.0年代,验证是通过Last-Modified这个HTTP头字段,根据文件的最后修改时间来判断的。但Last-Modified的最小时间单位是秒,所以如果文件的修改发生在一秒钟之内,那么这种机制就起不到效果了。

为了解决这个问题,HTTP/1.1协议引入了E-TAG字段,可以自定义文件修改的标志。Apache中的E-TAG默认设定为根据inode、文件大小、最后修改时间来确定。

进行验证时,浏览器把文件的上一次修改时间或者E-TAG值发送给服务器,服务器根据这个值来判断浏览器的缓存是否需要更新。如果需要更新,那么把文件的内容发送给浏览器,否则只发送304头,表示文件为修改。

缓存内容的即时更新

有些网站可能会要求客户端缓存的js/css/image文件能够即时更新,即一旦服务器端的文件做了修改,客户端在下次访问时就能获得更新,而不需要等缓存失效。

一个简单的方法是给每个静态文件加上后缀,比如是最后修改时间作为后缀,那么对一个abc.jpg文件的引用可能就变成http://www.xxx.com/image/abc.jpg?v=1221109171。手工生成这个后缀比较麻烦,如果网站使用脚本语言编程,那么可以把引用静态文件的HTML脚本改为动态编程语言,比如,把<imgsrc="/image/abc.jpg/>改为<?phpechoshow_image('/image/abc.jpg')?>,而show_image这个PHP函数可以定义成:

  
function show_image($img){
       return '<img src="'.$img.filemtime(WEB_ROOT.'/image/'.$img) . '"./>'
   }

总结

至此,我们实现了较好的客户端缓存,能够在必要时即时地更新缓存。如果不需要更新缓存,那么在缓存失效前,没有不必要的客户端与服务器之间的连接请求;在缓存失效后,如果文件的真实内容未发生改变,服务器只需要返回304头,最大限度地减少了网络流量。

相关推荐