This website requires JavaScript.

深入浅出浏览器缓存策略

2017.11.27 10:45字数 3104阅读 714喜欢 28评论 3

一: Expires

Expires是web服务器响应头字段,值是一个时间类型,告诉浏览器在过期时间前可以直接从浏览器缓存中取数据,而无需再次请求。

Expires是http 1.0的东东,在http1.1 + 的场景下,其作用基本可以忽略, 作用优先级最低

二: Cache-control

Cache-ControlExpires作用相当。只不过Cache-control更多灵活,且优先级高于Expires
Cache-Control可以设置的值有很多,下面列出最常用的几个:
no-cache: 所有内容都不会被缓存
no-store: 所有内容都不会被缓存到缓存或者internet临时文件中
max-age=xxx: 缓存的内容将在 xxx 秒后失效( 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高)

三: Last-Modified/If-Modified-Since

Last-Modified/If-Modified-Since要配合Cache-Control使用。
Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),则再次向web服务器请求时带上头 If-Modified-Since(= Last-Modified的值)。web服务器收到请求后将If-Modified-Since 与被请求资源的最后修改时间进行比对,决定返回304或者200(协商缓存)

四:Etag/If-None-Match

Etag/If-None-Match也要配合Cache-Control使用。
Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(比如md5 hash)。
If-None-Match:当资源过期时(使用Cache-Control标识的max-age), 则再次向web服务器请求时带上头If-None-Match (= Etag的值)。web服务器收到请求后将If-None-Match 则与被请求资源的相应校验串进行比对,决定返回304或者200(协商缓存)。


五: 既生Last-Modified何生Etag?

你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

  1. Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
  2. 如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存
  3. 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形
    Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-ModifiedETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

六: from disk cache和from memory cache

Chrome在高版本更新了缓存策略(具体版本忘记),原来的from cache变成了from disk cache(磁盘缓存)和from memory cache(内存缓存)两类,两者有什么区别呢?

先从官方文档来看下:

Chrome employs two caches — an on-disk cache and a very fast in-memory cache. The lifetime of an in-memory cache is attached to the lifetime of a render process, which roughly corresponds to a tab. Requests that are answered from the in-memory cache are invisible to the web request API. If a request handler changes its behavior (for example, the behavior according to which requests are blocked), a simple page refresh might not respect this changed behavior. To make sure the behavior change goes through, call handlerBehaviorChanged() to flush the in-memory cache. But don't do it often; flushing the cache is a very expensive operation. You don't need to call handlerBehaviorChanged() after registering or unregistering an event listener.

大概意思就是内存缓存是和渲染进程绑定的,大部分情况下于浏览器Tab对应(具体保存磁盘还是内存的逻辑不太清楚,如果有知道的请告知)。
由于内存缓存是直接从内存中读取的,所以速度更快,从图中可以看出时间是0ms。而磁盘缓存还需要从磁盘中读取,速度还和磁盘的I/O有关。

七:强缓存作用

强缓存作为性能优化中缓存方面最有效的手段,能够极大的提升性能。由于强缓存不会向服务端发送请求,对服务端的压力也是大大减小。
对于不太经常变更的资源,可以设置一个超长时间的缓存时间,比如一年。浏览器在首次加载后,都会从缓存中读取。
但是由于不会向服务端发送请求,那么如果资源有更改的时候,怎么让浏览器知道呢?现在常用的解决方法是加一个&v=xxx的版本后缀,在更新静态资源版本的时候,更新这个v的值,这样相当于向服务端发起一个新的请求,从而达到更新静态资源的目的。

八: 浏览器缓存与前端构建

为了追求最完美的缓存体验,通常web server(如nginx)会设置Cache-Control: max-age为一个很长的时间,所以为了让文件在更新时能及时的在浏览器避免缓存,前端资源在构建时需要做MD5文件指纹处理。