浏览器缓存问题

1. 两个概念

  1. 强缓存 用户发送的请求,直接从客户端缓存中获取,不发送请求到服务器,不与服务器发生交互行为。

  2. 协商缓存 用户发送的请求,发送到服务器后,由服务器判定是否从缓存中获取资源。

共同点: 客户端获得的数据最后都是从客户端缓存中获得

区别: 强缓存不与服务器交互,而协商缓存则需要与服务器交互。

2. 四个过程详解

2.1. (a)浏览器判定是否有缓存

所谓“客户端缓存”就是指用户设备中本地资源。不同浏览器缓存文件的地址也不尽相同。

对于一个html页面,缓存分3部分,一个是页面内容,一个是css样式,一个是JS文件

我们以chrome为例来查看下浏览器缓存文件的地址, 1)首先在chrome中输入:chrome://chrome-urls/,看到一堆列表,里面隐藏了许多浏览器的奥秘,有兴趣的可以自己深扒。 2)找到 chrome://cache(当然也可以直接输入这个地址)

2.2. (b)缓存是否过期

  • expires

Http1.0 中的标准,表明过期时间,注意此处的时间都是指的是服务器的时间。

存在的问题:服务器时间与客户端时间的不一致,就会导致缓存跟期待效果出现偏差。

  • Cache-Control Http1.1 中的标准,可以看成是 expires 的补充。使用的是相对时间的概念。 Cache-Control的属性:

    1)max-age: 设置缓存的最大的有效时间,单位为秒(s)。max-age会覆盖掉Expires

    1. s-maxage: 只用于共享缓存,比如CDN缓存(s -> share)。与max-age 的区别是:max-age用于普通缓存, 而s-maxage用于代理缓存。如果存在s-maxage,则会覆盖max-age 和 Expires.

    2. public:响应会被缓存,并且在多用户间共享。默认是public。

    3. private: 响应只作为私有的缓存,不能在用户间共享。如果要求HTTP认证,响应会自动设置为private。

    5)no-cache: 指定不缓存响应,表明资源不进行缓存。但是设置了no-cache之后并不代表浏览器不缓存,而是在缓存前要向服务器确认资源是否被更改。因此有的时候只设置no-cache防止缓存还是不够保险,还可以加上private指令,将过期时间设为过去的时间。

    6)no-store: 绝对禁止缓存。

    7)must-revalidate: 如果页面过期,则去服务器进行获取。

    所以判断缓存是否过期步骤是: 1) 查看是否有cache-control 的max-age / s-maxage , 如果有,则用服务器时间date值 + max-age/s-maxage 的秒数计算出新的过期时间,将当前时间与过期时间进行比较,判断是否过期 2)查看是否有cache-control 的max-age / s-maxage,则用expires 作为过期时间比较

总结:(b)过程执行完后,如果判定为未过期,则使用客户端缓存。那么就是属于“强缓存”。

2.3. (c)跟服务器协商是否使用缓存

到这一步的时候,浏览器会向服务器发送请求,同时如果上一次的缓存中有Last-modified 和 Etag 字段, 浏览器将在request header 中加入If-Modified-Since(对应于Last-modified), 和If-None-Match(对应于Etag)。

  • Last-modified: 表明请求的资源上次的修改时间。

  • If-Modified-Since:客户端保留的资源上次的修改时间。

  • Etag:资源的内容标识。(不唯一,通常为文件的md5或者一段hash值,只要保证写入和验证时的方法一致即可)

  • If-None-Match: 客户端保留的资源内容标识。

    1) 分布式系统尽量关闭Etag,因为每台机器生成的Etag都不一样。 2)分布式系统里多台机器间文件的Last-Modified必须一致,以免负载均衡不同导致对比失败。

通常情况下,如果同时发送 If-None-Match 、If-Modified-Since字段,服务器只要比较etag 的内容即可,当然具体处理方式,看服务器的约定规则。

2.4. (d)协商缓存

在这个阶段,服务器一般会将Cache-control、expires 、last-modified、date、etag 等字段在response header 中返回,便于下次缓存。当然具体的场景,也是看服务器的约定规则设定。

3. 缓存的不同来源

3.1. from disk cache

从磁盘中获取缓存资源,等待下次访问时不需要重新下载资源,而直接从磁盘中获取。它的直接操作对象为CurlCacheManager。

3.2. from memory cache

从内存中获取资源,等待下次访问时不需要重新下载资源,而直接从内存中获取。Webkit早已支持memoryCache。 目前Webkit资源分成两类,一类是主资源,比如HTML页面,或者下载项,一类是派生资源,比如HTML页面中内嵌的图片或者脚本链接,分别对应代码中两个类:    MainResourceLoader和SubresourceLoader。虽然Webkit支持memoryCache,但是也只是针对派生资源,它对应的类为CachedResource,用于保存原始数据(比如CSS,JS等),以及解码过的图片数据。

3.3. 区别

当退出进程时,内存中的数据会被清空,而磁盘的数据不会,所以,当下次再进入该进程时,该进程仍可以从diskCache中获得数据,而memoryCache则不行。

3.4. 相似

diskCache与memoryCache相似之处就是也只能存储一些派生类资源文件。它的存储形式为一个index.dat文件,记录存储数据的url,然后再分别存储该url的response信息和content内容。Response信息最大作用就是用于判断服务器上该url的content内容是否被修改。

3.5. 用户行为

4. 解决方案:

4.1.1. 1、页面内容

4.1.2. 2、CSS和JS文件

改成 就是只要在每次修改后改一下版本号即可

这样每次修改后都要改,有没有自动加版本号的东西,估计有,如果是JSP和php可以通过脚本 自动生成,如果是纯html也可以通过document.write,或者用动态加载JS的框架啥的。