0

八一八浏览器缓存

 2 years ago
source link: http://kangkona.github.io/818-browser-caching/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

八一八浏览器缓存

10/Sep 2014

Web

今天由于需求变更,修改了部分前端代码,测试没问题之后进行了部署。交付测试时,发现修改的代码不起作用。而且比较奇怪的是一般手机浏览器没有问题,但微信内嵌浏览器内的结果还停留在部署之前的状态。分析后得知应该是缓存机制引起的。这里总结一下关于浏览器缓存的知识。

1. 为什么需要浏览器缓存

网络的带宽总是有限的,尤其是在并发比较高的情况下,能节约一点儿是一点儿。对于大多数网站来说,类似js, css,图片等静态文件是很少变化的。我们便可以在用户的一次请求之后在本地缓存静态文件。用户进行同样的请求(url一致)时,相应文件直接在本地读取,快速获得响应。 除了减少服务器压力和带宽外,缓存机制还可以极大提高页面的显示速度。

2. 缓存协商

缓存的文件是由服务器生成,在本地保存, 但不是保存下来就万事大吉, 合理使用缓存需要双方动态沟通,这样就引入了缓存协商。下面是具体的请求过程分析:

   (1) 当浏览器第一次请求某个URL时,顺利访问的话,服务器返回状态200的状态, ; 同时会返回给浏览器一些Headers集合,
    如果只设定了Last-Modified和Etag头信息,那么浏览器接收到服务器这些信息后,就会将资源缓存在本地目录中,同时
    保存文件的上述信息.
   (2) 再次请求时,根据 HTTP 协议的规定,浏览器会向服务器传送 If-Modified-Since 与 If-None-Match 报头,这
    两个报头实际上是第一次请求时服务器返回的Last-Modified,Etag。发送这两个报头目地是询问服务器,该资源在
    时间内有没有被修改过。如 果该资源未被修改,则服务器会直接返回HTTP 304 (Not Changed.)状态码,内容为
    空,此时不会下载资源,浏览器则自动从缓存目录中读取资源。
   (3) 只使用Last-Modified和Etag 可以减少传输成本,但不会减少http请求数量。如果给文件加上关于过期时间(Expires)
    的header报文,这样浏览器就会先检查缓存中的文件,如果没有过期,就直接使用缓存中的文件,从而不会 发送http请求。 

3. 缓存存在的问题

   既然存在了本地,那么最大的问题就是一旦服务器的文件更新了,而浏览器还在使用本地的缓存,
   会造成服务器端的修改不能生效。 我们碰到的问题刚好可以对号入座。

4. 解决之道

4.1 设置html的缓存相关信息

在html的头部加入如下信息:

         <META HTTP-EQUIV="pragma" CONTENT="no-cache"> 

        <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"> 

        <META HTTP-EQUIV="expires" CONTENT="0"> 

如果是动态语言生成的页面可以类似设置:

        <% 
        // 将过期日期设置为一个过去时间 
        response.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT"); 
        // 设置 HTTP/1.1 no-cache 头 
        response.setHeader("Cache-Control", "no-store,no-cache,must-revalidate"); 
        // 设置 IE 扩展 HTTP/1.1 no-cache headers, 用户自己添加 
        response.addHeader("Cache-Control", "post-check=0, pre-check=0"); 
        // 设置标准 HTTP/1.0 no-cache header. 
        response.setHeader("Pragma", "no-cache"); 
        %> 

4.2 使用POST代替GET

根据 HTTP 规范,GET 用于信息获取,是幂等操作。也就是说,当使用相同的URL重复GET请求会返回预期的相同结果时,GET方法才是适用的。当对一个请求有副作用的时候(例如,提交数据注册新用户时),应该使用POST请求而不是GET。 所以浏览器会对GET请求做缓存处理。 不会对POST做缓存。

4.3 在url后加随机参数

在一次请求的URL后加随机数,服务器就会认为是不同的请求,就会传回最新的文件覆盖旧的文件。但这种方法仅限于动态语言。

    <%@ page import="java.util.Random"%>
    <html>  
    <head>
        <script src="js/fuck.js?<%=new Random().nextInt(1000);%>"></script>
    </head>
    ...
    </html>

4.4 给修改后的文件换个名字

上面的三种方法都是完全舍弃缓存优点的做法,如果既想使修改生效,又想继续使用缓存机制应该怎么办呢? 其实最简单的做法就是将修改过的文件换个名称,比如加个时间戳之类的东西。这是的文件就变成了新鲜出炉的文件,本地压根儿就没有,只得乖乖从服务器端获取。
这种方法理论上是行的通的,有时间我会试试,可惜我没有时间了。 你有时间不妨一试?

参考:
浅谈浏览器缓存
浏览器缓存url请求
浏览器缓存
百科


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK