引言
其实,缓存这一块的知识对于普通的只是以快速页面开放的同学来说,我想应该是一知半解。但是,很好地理解缓存地过程可以让我们更好地记忆 HTTP 状态码 和 HTTP 首部字段。正常的浏览器缓存的过程:
- 询问浏览器内存(Memory Cache)
- 询问本地磁盘缓存(Disk Cache)
- HTTP 缓存过程,即强缓存和协商缓存
当然如果是
HTTP/2
还可能会有Push Cache
;并且如果应用中使用了Service Work
的缓存,本次只讲解HTTP/1X
中的强缓存和协商缓存
浏览器缓存过程
浏览器缓存过程,它会分为强缓存和协商缓存。其实,从它们各自的名词就很容易理解它们各自需要描述的东西。
一、强缓存
描述:即服务端一方设定的可缓存内容,这个过程不需要沟通,只要这个缓存有效,那么你就可以去读取它。
缺点:其实这样简单的理解定义,就可以看出它的弊端,当服务端缓存的资源变了,可是浏览器缓存的资源还有效,那么这个资源的更新就没有即时同步,这无疑是不友好的。
强缓存有两种:Expires
和 Cache-Control
。
Expires
我想无论是前端或者后端同学,看到这个单词,应该都很容易的联想到 Cookie
的 Expires
,它在 Cookie
中作用就是设置 Cookie
的有效期。同样地,在这里它是 HTTP/1
中用来描述缓存资源有效时间的 HTTP 实体首部字段,它的值为 GMT
时间,由服务端定义好通过响应报文返回给前端。
缺点:其实看到最后一段话,大家应该可以看出它明显的不足,就是由服务端定义好时间,这就会发生服务端和客户端时间不一致的问题。
Cache-Control
Cache-Control
它是 HTTP/1.1
中提出用于缓存的 HTTP 通用首部字段。它则代表资源在一段时间内可以读取缓存,而不用重新请求。而与 Expires
不同,它的值为 max-age
= **s
,并且它还可以搭配一些指令实现一些特定的效果,例如:
private
,表示HTTP
请求从浏览器发送到最终的服务器这个过程,只有浏览器缓存,中间任何传递节点不能缓存(代理服务器之类的)public
,表示都可以缓存,无论浏览器、服务器或者代理服务器。no-store
,表示不需要缓存。no-cache
,表示不使用强缓存,使用协商缓存。max-age
,表示缓存有效的最大时间,单位为s
。s-maxage
,表示代理服务器的缓存有效的最大时间。max-stale
,表示浏览器可接受的失效缓存的最大失效时间。max-refresh
,表示浏览器可接受的最短更新时间,不过这个时间是当前的age
加上max-refresh
。
当
Expires
和Cache-Control
同时存在时,Cache-Control
的优先级较高
二、协商缓存
描述:即这个缓存的过程需要通过双方的确认,才能决定缓存资源是否可用,可用则返回状态码 304 Not Modified
,不可用则返回状态码 200 OK
和更新后的资源。
缺点:因为缓存的最终确定需要浏览器和服务器双方的确定,所以性能较低、耗时较长。
Last-Modified
Last-Modified
是 HTTP/1.0
中用于协商缓存的 HTTP 响应首部字段,它表示该资源的最后修改时间,它会和 If-Modified-Since 一起使用。
这个过程大致是这样的,服务端在响应报文中添加 Last-Modified
首部字段即相应的值(同样是 GMT
时间),然后浏览器在接受响应后,会将资源进行缓存和记录 Last-Modified
,在下次请求相同资源的时候添加 If-Modified-Since
HTTP 请求首部字段 携带之前记录的 Last-Modified
的值一起发送到服务端,服务端识别到 If-Modified-Since
字段,并与该资源上次修改的时间进行比较,如果相同则返回状态 304 Not-Modified
,如果不同则发送状态码 200 OK
以及在报文实体中携带上更新过的资源。
缺点:
- 在浏览器本地可以修改资源,并且此时该资源对应的
Last-Modified
也会随着变化,那么此时就会造成服务端返回状态码200 OK
情况和返回没有更新的资源,即这个请求完全没有意义。 Last-Modified
无法观察低于秒时的文件的修改,那么这就会造成文件已经更新了,但是服务端却认为它没有更新状态304 Not-Modified
,让浏览器去读缓存,即资源更新不精确。
ETag
ETag
是 HTTP/1.1
中用于协商缓存的 HTTP 响应首部字段,它是由服务端为该资源生成的 Hash
,她会和 If-No-Match 一起使用。
它的过程会是这样,服务端在响应报文中添加 ETag
首部字段及对应资源的 Hash
,同样地,然后浏览器在接受响应后,会将资源进行缓存和记录 ETag
,在下次请求相同资源时通过 If-No-Match
HTTP 请求首部字段 携带之前记录的 ETag
的值一起发送到服务端,服务端识别到 ETag
字段,并于该资源此时的 Hash
值进行比较,如果相同返回状态码 304 Not-Modified
,如果不同则发送状态码 200 OK
以及在报文实体中携带上更新过的资源。
缺点:
ETag
需要服务端计算资源生成Hash
,这个过程无疑是比较慢的,所以性能较低。
当
ETag
和If-Modified
同时存在时,ETag
的优先级较高
总结
虽然,强缓存和协商缓存只是浏览器缓存过程一部分,但是阅读起来知识点其实不少,如文章开头提到的 HTTP
状态码、HTTP
首部字段、以及浏览器请求 URL
的这个过程,都或多或少会涉及到一些。不过,大家在阅读的过程不需要任何负担,其实整个缓存的过程就只有几个单词,前人在定义这些单词的时候,并非随意为之,每一个都有它的意义,这些单词就是我们阅读时的记忆点。所以,大家放平常心从这些单词出发,自然而然就会构建整个缓存的过程在记忆中。