赞
踩
HTTP缓存机制是优化web性能的重要手段,也是优化用户体验的重要一环。了解和熟悉HTTP缓存机制也成为了前端工作者必不可少的技能。
HTTP缓存是用于临时存储网页资源(如HTML页面、图像等),以减少服务器延迟的一种技术。HTTP缓存系统会保存下通过这套系统的文档的副本;如果满足某些条件,则可以由缓存满足后续请求。HTTP缓存系统既可以指设备,也可以指计算机程序。
HTTP缓存可分为强制缓存和协商缓存。
**强制缓存:**直接使用客户端缓存,不从服务器拉取新资源,也不验证缓存资源是否过期。返回的状态码为200(OK)。
**协商缓存:**通过服务器验证资源有效性,资源有效则返回304(Not Modified),资源失效则返回最新的资源文件。
HTTP主流的有三个版本:HTTP/1.0、HTTP/1.1、HTTP/2.0。其中HTTP/1.0和HTTP/1.1的应用最为广泛。HTTP/2.0因对缓存机制的改动有别于HTTP/1.0和HTTP/1.1,因此HTTP/2.0相关内容会在文末总结部分进行介绍。HTTP/1.0与HTTP/1.1可根据缓存类别区分如下:
HTTP版本 | 强制缓存 | 协商缓存 |
---|---|---|
HTTP/1.0 | Expires | Last-Modified |
HTTP/1.1 | Cache-Control | ETag |
Expires
的值为服务端返回的到期时间,是一个GMT
(格林尼治标准时间)绝对时间,如:Tue, 17 Jan 2023 03:48:45 GMT
。下一次请求时,客户端判断当前系统GMT
时间是否小于缓存携带的GMT
时间。若小于,直接使用缓存数据,否则从服务器请求新的文件。
不过Expires
存在的问题也显而易见。
首先,使用客户端获取的GMT
时间与服务器GMT
时间作比较,如果客户端主动修改了系统时间,就会出现缓存命中的误差。
其次,GMT
时间是基于格林尼治天文台测算时间后,每隔一小时想全世界发放调时信息。观测本身存在的误差以及非实时的同步机制,都可能会导致出现缓存命中的误差。
所以在HTTP/1.1版本中,使用Cache-Control
中的max-age
替代。
Cache-Control
是HTTP/1.1中重要的缓存规则。它可以在HTTP请求头和响应头中使用,提供了多样化的配置参数。同时也可以适用于更广泛的复杂场景。
指令格式具有以下有效规则:
- 不区分大小写,但建议使用小写。
- 多个指令以逗号分隔。
- 具有可选参数,可以用令牌或者带引号的字符串语法。
常用的指令如下:
Expires
,客户端会判断资源已缓存的时长是否小于设置的max-age
时长。是则直接使用缓存数据,否则会进行Expires
的判断流程。max-age
和Expires
,仅适用于缓存服务器。客户端缓存失效后会向服务器进行进行缓存有效性验证,这个缓存有效性验证的过程就是协商缓存
。若资源有效,则返回304(Not Modified)
。客户端拿到304
状态码后会再从本地缓存中获取资源。整个请求响应过程是与无缓存流程一样的。相对于无缓存流程的优势在于仅响应状态码后,客户端直接从本地缓存获取文件,而无需进行文件下载。减少了网络响应的文件大小,进而加快了网络响应速度。
协商缓存的请求和响应是需要相互配合的,可组合使用。如下表:
版本\阶段 | 请求 | 响应 |
---|---|---|
HTTP/1.0 | If-Modified-Since/If-Unmodified-Since | Last-Modified |
HTTP/1.1 | If-None-match/If-Match | E/Tag |
协商缓存会先判断请求头中是否携带no-store
。如果携带,则直接返回最新的服务器文件。
客户端第一次向服务器请求资源时,服务器会返回资源。同时会在响应头中添加Last-Modified
字段来表明资源的最后修改时间。当客户端强制缓存失效后,会重新向服务器进行缓存有效性验证。在验证的请求头中,会添加If-Modified-Since
字段。服务器会对请求头中的If-Modified-Since
和其存储的资源Last-Modified
进行比较。若If-Modified-Since
的时间不小于Last-Modified
,则资源有效,返回304(Not Modified)
。否则返回资源本身,并且重新记录文件的Last-Modified
。
Last-Modified
:响应头携带的资源最后修改时间。格式为last-modified:GMT
。
如:last-modified: Sat, 14 Jan 2023 08:40:00 GMT
If-Modified-Since
:请求头携带的资源是否在某个时间后有修改。服务器会使用此值和其本身存储的时间进行比较。格式为:If-Modified-Since:GMT
。只可以用在 GET
或 HEAD
请求中。
If-Unmodified-Since
:请求头携带的资源是否在某个时间后没有修改。格式为:if-unmodified-since:GMT
。有别于If-Modified-Since
,If-Unmodified-Since
被用于POST
或其他非简单请求。如果在If-Unmodified-Since
指定的时间内有过修改,则返回412(Precondition Failed)
。
Last-Modified
也是存在严重问题的。
首先,Last-Modified
只关注文件的最后修改时间,和文件内容无关。所以文件内容在修改后又重新恢复,也会导致文件的最后修改时间改变。此时客户端的请求则无法使用缓存。
其次,Last-Modified
只能监听到秒级别的文件修改,如果文件在1秒内进行了多次修改,那么响应头返回的Last-Modified
的时间是不变的。 此时客户端因接收到响应304
,会导致资源无法及时更新,使用缓存的资源文件。
因此HTTP/1.1使用了ETag
来进行缓存协商。
为了解决上述Last-Modified
可能存在的不准确的问题,HTTP/1.1推出了新的响应字段ETag
来进行协商缓存。ETag
的优先级比Last-Modified
高。
服务器接收到浏览器请求后,会先进行If-None-Match
与ETag
值的比较。若相等,则资源有效,返回304(Not Modified)
。否则返回资源本身,并且重新记录文件的ETag
。
ETag
:响应头携带的资源标识符。格式为ETag:ETag-value
可由服务器自行设置算法生成,通常是使用内容的散列或简单的使用版本号。
如:etag: "I82YRPyDtSi45r0Ps/eo8GbnDfg="
If-None-Match
:请求头携带的是否无匹配文件字段。优先级高于Last-Modified
。当服务器没有任何资源的ETag
与请求头携带的ETag
值完全一样时,返回最新的资源,否则服务器会返回304。
如: if-none-match:"I82YRPyDtSi45r0Ps/eo8GbnDfg="
If-Match
:请求头携带的是否存在匹配文件字段。对于简单请求需要搭配 Range
首部使用。对于非简单请求,如PUT
,可用于上传ETag
。
如: if-match:"I82YRPyDtSi45r0Ps/eo8GbnDfg="
通过前文,我们了解到 HTTP 缓存主要分:强制缓存、协商缓存。
强制缓存由Exipres(HTTP/1.0)、 Cache-Control(HTTP/1.1)控制。客户端直接读本地缓存,不会再跟服务器端交互,状态码 200。
协商缓存由 Last-Modified / If-Modified-Since(HTTP/1.0), Etag /If-None-Match(HTTP/1.1)进行有效性验证,每次请求需要让服务器判断一下资源是否更新过,从而决定客户端是否使用缓存,如果是,则返回 304,否则返回最新文件。
HTTP/2.0中设计了新的缓存方式,服务器推送(Push Server)。有别于强制缓存和协商缓存,属于推送缓存。这种新的缓存方式主要是为了解决客户端缓存时效性的问题,即还没有收到客户端的请求,服务器就把各种资源推送给客户端。比如,客户端只请求了a.html,但是服务器把a.html、a.css、a.png全部发送给客户端。这样的话,只需要一次请求,客户端就更新了所有文件的缓存,提高了缓存的时效性。
GMT(维基百科):https://en.wikipedia.org/wiki/Greenwich_Mean_Time
HTTP缓存(MDN):https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching
转转研发中心及业界小伙伴们的技术学习交流平台,定期分享一线的实战经验及业界前沿的技术话题。
关注公众号「转转技术」(综合性)、「大转转FE」(专注于FE)、「转转QA」(专注于QA),更多干货实践,欢迎交流分享~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。