一、为什么要使用缓存
Web缓存可以自动保存已获取的资源,当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地存储而不是原始服务器中提取这些资源,使用缓存有下列有点:
- 缓存减少了冗余的数据传输
- 缓存缓解了网络瓶颈问题,节省带宽
- 缓存降低了对原始服务器的压力
- 缓存降低了距离时延
二、各种类型的缓存
缓存大体可以分为两种类型:私有缓存和公有缓存。 私有缓存是个人的缓存,包含了单个用户最常用的资源;公有缓存包含了多个用户常用的资源。
1、私有缓存
大多数浏览器都会将常用文档缓存在个人电脑的磁盘或者内存中,这样可以避免再次向服务器发起多余的请求。你可以在浏览器的设置中配置缓存的各种设置。
2、公有代理缓存
公有代理缓存会接受来自多个用户的访问,代理缓存会从本地缓存中提供文档,或者代表用户和服务器进行联系。
三、缓存的处理步骤
常见的HTTP缓存只能存储GET响应,对其他累着的响应则无能为力。Web缓存的基本工作原理大多很简单,处理过程包括7个步骤。
1、接收 - 缓存图片请求报文
2、解析 - 缓存对请求报文进行解析,提取出URL和各种首部
3、查询 - 缓存查看是否有本地副本可用,如果没有就从服务器获取一份副本,并将其保存在本地
4、新鲜度检测 - 如果本地有副本,缓存就会查看已缓存副本是否足够新鲜,如果不是,就询问服务器是否有任何更新
5、创建响应 - 如果资源没有更新,缓存会用新的首部和已缓存的主体来构建一条响应报文
6、发送 - 缓存通过网络将响应发回给客户端
7、日志 - 缓存可选地创建一个日志文件条目来描述这个事务
缓存GET请求流程图

四、新鲜度检测
1、如何判断文档是否已过期
理论上当一个资源被缓存存储后,该资源可以永久存储在缓存中,但是缓存的空间毕竟有限,所以缓存会定期将一些副本清除。浏览器如何判定缓存的副本需要清除了?
服务端在返回一个资源时会为这个定一个过期时间,服务器通过HTTP Cache-Control:max-age和Expires首部为每一个文档附加一个“过期时间”。在文档过期之前,缓存可以无需与服务器联系而使用这些副本,除非客户端请求报文中包含有阻止提供已缓存或未验证资源的首部。
Expires

Cache-Contirl:max-age

2、过期文档在验证
有时候缓存里的文档副本已过期,但并不意味着服务器上的文档已更新。缓存可以通过一些条件请求首部到服务端去验证文档是否有更新,只有当服务端文档和缓存中的文档不同时,响应才会返回主体。
对缓存再验证最有用的2个首部是If-Modified-Since和If-None-Match。
If-Modified-Since:Date
请求报文中If-Modified-Since会带上上一次响应返回的Last-Modified日期,只有在这个日期之后资源发生了变化才会指示服务器执行请求。
- 如果在指定日期后,文档被修改,GET请求就会成功执行。响应会携带新的首部和新文档返回,新首部中就包括新的过期时间(Last-Modified)。
- 如果自指定日期后,文档没有被修改,服务器会返回一个304 Not Modified响应报文,为了提高有效性,不会返回文档的主体,一般还会返回一个新的过期时间(Last-Modified)。
If-Modified-Since: < cached last-modified date >
If-None-Match
有时候仅使用最后修改日期来验证还是不够。比如有些文档可能被重写,内容没有变化,但最后修改日期会发生变化。这个时候可以使用ETag(实体标签)来进行比较。ETag类似于文档的序列号或版本好,当文档修改时,可以修改文档的实体标签来说明这是个新的版本。
请求头If-None-Match可以带上上次返回的ETage,来去服务端验证文档是否有修改过。如果修改过,服务端会返回200,如果没有修改过,服务端会返回304 Not Modified,但不返回body。304的响应头也可以同时更新缓存文档的过期时间。
如果服务器返回一个实体标签,客户端就必须使用If-None-Match来验证。如果服务器只返回一个Last-Modified值,客户端就可以使用If-Modified-Since验证。如果Etag和Last-Modified都提供了,客户端就应该使用着两种方案验证。
Etag / If-None-Match(优先级高于Last-Modified / If-Modified-Since)
五、控制缓存的能力
HTTP/1.1定义的 Cache-Control头用来区分对缓存机制的支持情况, 请求头和响应头都支持这个属性。 可以替换之前用来定义响应缓存策略的标头(例如Expires)
- 每个资源都可通过 Cache-Control HTTP 标头定义其缓存策略
- Cache-Control 指令控制谁在什么条件下可以缓存响应以及可以缓存多久。
禁止进行缓存
Cache-Control: no-store
Cache-Control: no-cache, no-store
Pragma: no-cache
“no-store”直接禁止浏览器以及所有中间缓存存储任何版本的返回响应;
不仅不能缓存, 连暂存也不可以(即: 临时文件夹中不能暂存该资源)
“no-cache”表示必须先与服务器确认返回的响应是否发生了变化,然后才能使用该响应来满足后续对同一网址的请求。 因此,如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应,但如果资源未发生变化,则可避免下载;
数据内容不能被缓存, 每次请求都重新访问服务器, 若有max-age, 则缓存期间不访问服务器.
Pragma 是HTTP/1.0标准中定一个的一个header属性,请求中包含Pragma的效果跟在头信息中定义Cache-Control: no-cache相同,但是HTTP的响应头不支持这个属性。通常定义Pragma以向后兼容基于HTTP/1.0的客户端。
强制确认缓存
Cache-Control: must-revalidate
“must-revalidate”规定每次有请求发出时,缓存会将此请求发到服务器,服务器端会验证请求中所描述的缓存是否过期,若未过期返回304,缓存使用本地缓存副本。
私有缓存和公共缓存
Cache-Control: private
Cache-Control: public
如果响应被标记为“public”,则即使它有关联的 HTTP 身份验证,甚至响应状态代码通常无法缓存,也可以缓存响应。 大多数情况下,“public”不是必需的,因为明确的缓存信息(例如“max-age”)已表示响应是可以缓存的。
相比之下,浏览器可以缓存“private”响应。 不过,这些响应通常只为单个用户缓存,因此不允许任何中间缓存对其进行缓存。 例如,用户的浏览器可以缓存包含用户私人信息的 HTML 网页,但 CDN 却不能缓存。
缓存过期机制
Cache-Control: max-age=31536000
过期机制中,最重要的指令是 "max-age=",表示资源能够被缓存(保持新鲜)的最大时间。相对Expires而言,max-age是距离请求发起的时间的秒数。针对应用中那些不会改变的文件,通常可以手动设置一定的时长以保证缓存有效,例如图片、css、js等静态资源。