对浏览器缓存这一块一直是乱哄哄的状态,今天终于有时间整理一下,写下这篇笔记,以供日后查阅。
缓存概述
良好的缓存策略可以降低资源的重复加载提高网页的整体加载速度 通常浏览器缓存策略分为两种:强缓存和协商缓存
基本流程
浏览器在加载资源时,根据请求头的 expires 和 cache-control 判断是否命中强缓存,是则直接从缓存读取资源,不会发请求到服务器。
如果没有命中强缓存,浏览器一定会发送一个请求到服务器,通过 last-modified 和 etag 验证资源是否命中协商缓存,如果命中,服务器会将这个请求返回,但是不会返回这个资源的数据,依然是从缓存中读取资源
如果前面两者都没有命中,直接从服务器加载资源
相同点
如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;
不同点
强缓存不发请求到服务器,协商缓存会发请求到服务器。
强缓存
强缓存通过 Expires 和 Cache-Control 两种响应头实现
Expires
Expires 是 http1.0 提出的一个表示资源过期时间的 header,它描述的是一个绝对时间,由服务器返回。Expires 受限于本地时间,如果修改了本地时间,可能会造成缓存失效
Expires: Sat, 29 Sep 2018 14:20:00 GMT
Cache-Control
Cache-Control 出现于 HTTP / 1.1,优先级高于 Expires , 表示的是相对时间
Cache-Control: max-age=315360000
Cache-Control 在 request 和 response 中都可以使用
在请求中使用 Cache-Control 时,它可选的值有:
在响应中使用 Cache-Control 时,它可选的值有:
强缓存流程图
协商缓存
当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的 http 状态为 304 并且会显示一个 Not Modified 的字符串
协商缓存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对 Header 来管理的
Last-Modified,If-Modified-Since
Last-Modified 表示请求来的文件的最后修改日期,浏览器会在 request header 加上 If-Modified-Since(上次返回的 Last-Modified 的值),询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来。
ETag、If-None-Match
Etag 就像一个指纹,资源变化都会导致 ETag 变化,跟最后修改时间没有关系,ETag 可以保证每一个资源是唯一的
If-None-Match 的 header 会将上次返回的 Etag 发送给服务器,询问该资源的 Etag 是否有更新,有变动就会发送新的资源回来
ETag 的优先级比 Last-Modified 更高
大致流程
客户端请求一个页面(A)。
服务器返回页面 A,并在给 A 加上一个 Last-Modified/ETag。
客户端展现该页面,并将页面连同 Last-Modified/ETag 一起缓存。
客户再次请求页面 A,并将上次请求时服务器返回的 Last-Modified/ETag 一起传递给服务器。
服务器检查该 Last-Modified 或 ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应 304 和一个空的响应体。
感觉两个功能重复了?
ETag 对 Last-Modified 的补充
首先 Last-Modified 在 http/1.0 中被提出,而在 http/1.1 中提出的 ETag 则是为了解决 Last-Modified 无法解决的一些问题
一些文件也许会周期性的更改,但是他的内容并不改变 (仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新 GET;
某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说 1s 内修改了 N 次),If-Modified-Since 能检查到的粒度是 s 级的,这种修改无法判断 (或者说 UNIX 记录 MTIME 只能精确到秒);
某些服务器不能精确的得到文件的最后修改时间。
Last-Modified 对 ETag 的补充
一些图片等静态文件的修改,如果每次扫描内容生成 ETag 来比较,显然要比直接比较修改时间慢很多
小结
所以说两者并不是互斥,而是相辅相成的关系,既可以单独使用,又可以同时使用。
同时传入服务器时,服务器可以根据自己的缓存机制的需要,选择 ETag 或者是 Last-Modified 来做缓存判断的依据,甚至可以两个同时参考。
如何使用
协商缓存需要配合强缓存使用,如果不启用强缓存的话,协商缓存根本没有意义
大部分 web 服务器都默认开启协商缓存,而且是同时启用【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】
Apache 对于静态内容默认会返回 Last-modified 和 ETag.Nginx 只会返回 Last-modified(可配置 etag on 开启).
但是下面的场景需要注意:
分布式系统里多台机器间文件的 Last-Modified 必须保持一致,以免负载均衡到不同机器导致比对失败;
分布式系统尽量关闭掉 ETag(每台机器生成的 ETag 都会不一样)
整体流程图
参考
https://github.com/amandakela…https://blog.csdn.net/u012375…https://segmentfault.com/q/10…baidu and google
原文在这里