最近我在做前端面试题总结系列,感兴趣的朋友可以添加关注,欢迎指正、交流。
争取每个知识点能够多总结一些,至少要做到在面试时,针对每个知识点都可以侃起来,不至于哑火。
通过前面的介绍,我们知道 HTTP 缓存分为两种:
在上一篇文章中,我们了解了 HTTP 强缓存,今天我们来了解一下协商缓存相关的内容。
协商缓存,也称为对比缓存,从名称可以看出,它没有强制缓存那么霸道,可以有商有量的来确定是否使用缓存资源。
协商缓存机制下,浏览器需要发送缓存标识,去向服务器验证缓存标识是否有效,进而判断是重新发起请求、下载完整的响应,还是从本地获取缓存的资源。
如果服务端提示缓存资源未改动(Not Modified),资源会被重定向到浏览器缓存,这种情况下网络请求对应的状态码是 304,比如:
协商缓存的整体规则如下所示:
从上图可以看出,虽然客户端仍然发起了 HTTP 请求服务器,但是服务器只做了标志对比来确认是否使用缓存,如果确认使用缓存,就不会再返回具体的资源了。这样做虽然没有减少请求数量,但是极大减小了请求负荷,可以明显提升请求速度和减小网络带宽。
上图是缓存标识正常有效的时序图,但其实协商缓存的验证结果也存在两种情况:
协商缓存需要配合强缓存使用,使用协商缓存需要先设置 Cache-Control:no-cache 或者 pragma:no-cache 来告诉浏览器不走强缓存。
对于协商缓存来说,缓存标识的传递是我们着重需要理解的,它在 Response Header 和 Request Header 之间进行传递。
缓存标识可以分为两类:
我们一般会说,协商缓存的缓存标识是 Last-Modified(最后修改时间) 和 Etag(标签或名称),因为它们两个都是由服务端确定并返回的。
浏览器携带的是具有判断意味的属性 —— If-Modified-Since(从什么时间以来是否改变) 和 If-None-Match(是否匹配不到)。
缓存标识的携带位置如下图所示:
在具体的网络请求中,缓存标识如下图所示:
Last-Modified 和 If-Modified-Since 是 HTTP 1.0 引入的。
当浏览器第一次访问一个资源的时候,服务器会在 Response 、Header 中返回一个 Last-Modified,代表这个资源最后的修改时间。
再次请求服务器时,请求头会携带此字段,值为上次请求时服务器返回的 Last-Modified 的值。
服务器收到请求后发现有头 If-Modified-Since 则与被请求资源的最后修改时间进行比对:
使用 Last-Modified 是有一定缺陷的:
为了解决上面服务器没有正确感知文件变化的问题,Etag 作为 Last-Modified 的补充出现了。
Etag 和 If-None-Match 是一对报文头,属于HTTP 1.1。
ETag 和 If-None-Match 的值是一串 hash 码,代表的是一个资源的标识符,当服务端的文件变化的时候,它的 hash 码会随之改变。
服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。
ETag 又有强弱校验之分,如果 hash 码是以 “W/” 开头的一串字符串,说明此时协商缓存的校验是弱校验的,只有服务器上的文件差异(根据 ETag 计算方式来决定)达到能够触发 hash 值后缀变化的时候,才会真正地请求资源,否则返回 304 并加载浏览器缓存。
再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。
服务器收到请求后发现有头 If-None-Match 则与被请求资源的唯一标识进行比对:
Etag 的生成过程需要服务器额外付出开销,会影响服务端的性能,这是它的弊端。
因此启用 Etag 需要我们审时度势:
总结一下上面的内容:
以上就是 HTTP 协商缓存的相关内容。
~
~本文完,感谢阅读!
~
学习有趣的知识,结识有趣的朋友,塑造有趣的灵魂!
你来,怀揣期望,我有墨香相迎! 你归,无论得失,唯以余韵相赠!
知识与技能并重,内力和外功兼修,理论和实践两手都要抓、两手都要硬!