这是我参与「第四届青训营 」笔记创作活动的的第4天
缓存是什么
缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。浏览器缓存时指浏览器对之前请求过的文件进行缓存,以便下一次访问时重复使用,节省带宽,提高访问速度,降低服务器压力
http 缓存机制主要在首部字段设定,相关的首部字段有:
- 通用首部字段(请求报文和响应报文两方都会使用的首部)
- Cache-Control :控制缓存的行为
- 请求首部字段(从客户端向服务器发送请求报文时使用的首部。补充了请求的附加内容,客户端信息,响应内容相关优先级等信息)
- If-Modified-Since :缓存资源的最后修改日期时间
- If-None-Match :比较实体标记(ETag)
- 响应首部字段(从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息)
- Etag :资源的匹配信息
- 实体首部字段(针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间与实体有关的信息)
- Expires :实体主体过期的日期时间
- Last-Modified :服务器上资源的最后修改日期时间
首部字段在哪
当客户端向服务器端以发送请求报文的形式发送请求后,接收到请求的服务器,会将请求内容的处理结果以响应报文的形式返回。首部字段就在响应报文的报文首部
缓存策略
图源:前端基础-浏览器缓存/HTTP缓存机制(面试常考)
初次请求时,浏览器作为客户端会先在浏览器缓存中查找该请求的结果以及缓存标识,如果没有则向服务器发起请求,服务器返回资源和200状态码及缓存标识给客户端,客户端将资源和缓存标识存入浏览器缓存
图源:http面试必会的:强制缓存和协商缓存
再次请求相同的网页时,流程如图所示。
- 比较当前时间与上一次返回 200 时的时间差,如果没有超过Cache-Control设置的 max-age,则没有过期,由于强制缓存优先级较高,命中强缓存,直接从本地读取资源
- 如果浏览器不支持HTTP1.1,则使用 expires 判断是否过期, expires 是http1.0的规范,它的值是一个绝对时间的GMT时间字符串,弊端在于服务端会把当地的时间转化为 GMT 时间,假设当前时间点为x,想缓存的时间为y,expires 会设置为x+y,如果浏览器时间不准,实际不是x,缓存时间也就不是y,http1.1改为用max-age,浏览器就会自己在本地计算过期时间,因此同时存在 max-age 和 Expires 会用 max-age
- 如果资源已过期,表明强制缓存没有被命中,开始协商缓存,向服务器发送带有 If-None-Match 和 If-Modified-Since 的请求
- 服务器收到请求后,优先根据 Etag 的值判断被请求的文件有没有做修改,Etag 值一致则没有修改,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200
- 如果服务器收到的请求没有 Etag 值,则将 If-Modified-Since 和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 last-modified 和文件并返回 200
小结
首先通过Cache-Control验证强缓存是否可用
- 如果强缓存可用,直接使用
- 否则进入协商缓存,发送HTTP请求,服务器通过 If-Modified-Since 或 If-None-Match 这些条件请求字段检查是否更新
- 若资源更新,返回资源和200状态码
- 若资源未更新,返回304,告诉浏览器直接从缓存获取资源
缓存类别
浏览器缓存分为强制缓存和协商缓存
强制缓存
强制缓存即若缓存资源有效,则直接使用缓存资源,不必再向服务器发起请求,直接从本地缓存中读取文件并返回Status Code: 200 OK。
- 200 form memory cache:不访问服务器,从内存中读取缓存,浏览器关闭后,数据不存在(资源被释放),再次打开相同页面,不会出现from memory cache
- 200 from disk cache:不访问服务器,从硬盘中读取缓存,浏览器关闭后,数据依然存在,再次打开相同页面,仍然出现from disk cache
- 优先访问 memory cache ,其次是 disk cache ,最后是请求网络资源
强制缓存的情况
- 不存在该缓存结果和缓存标识,强制缓存失效,则直接向服务器发起请求(跟第一次发起请求一致)。
- 存在该缓存结果和缓存标识,但该结果已失效,强制缓存失效,则使用协商缓存。
- 存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回该结果
有关首部字段
- Expires( http1.0 规范)
- 浏览器第一次请求资源时,服务器的返回的响应报文的首部字段会附上 Expires ,下一次请求此资源时,会根据上次的 Expries 字段决定是否直接使用缓存资源(请求时间小于服务器返回的到期时间),弊端上面提到过
- Cache-Control( http1.1 规范)
- 由于上文所述弊端,http1.1 规范中,提出了 Cache-Control 字段,且优先级高于 Expires ,值是相对时间
| 设置值 | 作用 |
|---|---|
| max-age | 设置资源可以被缓存多长时间,单位为秒 |
| s-maxage | 和max-age一样,但这个是设定代理服务器的缓存时间 |
| public | 所有内容都将被缓存(客户端和代理服务器都可缓存) |
| private | 内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存) |
| no-cache | 储存在本地缓存区中,在与原始服务器进行新鲜度再验证之前,缓存不能将其提供给客户端使用 |
| no-store | 不缓存任何数据 |
协商缓存
没有命中强制缓存的情况下,如果设置了协商缓存,这个时候协商缓存就会发挥作用了。 它是一种服务端的缓存策略,即通过服务端来判断某件是否可以被缓存。
协商缓存的情况
- 协商缓存生效,返回304
- 协商缓存失效,返回200和请求结果结果
有关首部字段
http面试必会的:强制缓存和协商缓存 浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,控制协商缓存的首部字段:
- Last-Modified / If-Modified-Since
- Last-Modified 即服务器上实际资源的最后修改日期时间,If-Modified-Since 即浏览器端缓存页面的最后修改时间
- 资源过期时(浏览器判断 Cache-Control 标识的 max-age 过期),发现响应报文首部字段有 Last-Modified 声明,则再次向服务器请求并携带 if-modified-since ,表示请求时间。服务器收到请求发现首部字段 if-modified-since ,则将其与 Last-Modified 对比,如 Last-Modified 距离现在更近,说明最后实际页面修改时间比缓存页面最后修改实际更晚,也就是说页面有更新,则返回最新资源与200状态码,否则返回304,使用缓存资源
-
Etag / If-None-Match
- Etag属于HTTP1.1属性,由服务器( Apache 或者其他工具)生成返回给客户端,用来帮助服务器控制Web端的缓存验证,Apache中,Etag 的值默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的
- 当资源过期时,浏览器发现响应报文首部字段有 Etag ,则再次向服务器请求时携带 If-None-Match (值等于 Etag )。服务器收到进行比对,如果有变化说明有新资源,返回200状态码,无变化说明可以使用缓存资源,返回304
-
Etag / If-None-Match 的优先级比 Last-Modified / If-Modified-Since 高
Etag 与 last-modified对比
-
Last-Modified 标注的最后修改时间只能精确到秒级,如果文件在一秒内被修改多次,即使文件改变,但 Last-Modified 不会改变,可能造成缓存命中不精确
-
本地打开缓存文件,即使没有对文件进行修改,还是会造成 Last-Modified 被修改,服务端不能命中缓存导致发送相同的资源
-
有些服务器不能精确获取文件的最后修改时间,因此 Last-Modified 可能造成缓存命中不精确
-
Etag 属性是资源生成的唯一标识符,当资源发生改变的时候,Etag 值也会发生改变,比 Last-Modified 方式更加精确
-
如果资源被重复生成,而内容不变,则Etag更精确。
-
Last-Modifed / If-Modified-Since 是http1.0出现的首部字段,而 ETag / If-None-Match 是 http1.1 出现的首部字段
-
Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高
-
使用协商缓存的时候,服务器需要考虑负载平衡的问题,因此多个服务器上资源的 Last-Modified 应该保持一致,因为每个服务器上 Etag 的值都不一样,因此在考虑负载平衡时,最好不要设置 Etag 属性