HTTP缓存策略

244 阅读7分钟

HTTP缓存策略

概览

在浏览器中打开一个页面时,浏览器会根据你输入的URL到对应的服务器上请求你想要的数据资源。但这个过程中可能页面可能需要等待一段时间去成功获取并完成处理后(白屏时间)才能渲染到你的页面中。有一个良好的缓存策略可以减低重复资源的请求,降低服务器的开销,提高用户页面的加载速度。

通常情况下,我们的缓存主要是针对html,css,img等静态资源,不会去缓存一些动态资源,因为缓存动态资源的话,数据的实时性就不会不太好,所以一般都只会去缓存一些不太容易被改变的静态资源。

作用和缺点

作用:

  • 减少不必要的网络传输,节约成本
  • 更快的页面加载速度
  • 减少服务器负载,避免服务器过载的情况出现

缺点:

  • 占用内存

强缓存

强缓存主要使用Expires、Cache-Control 两个请求头字段,两者同时存在 Cache-Control 优先级更高。当命中强缓存的时候,客户端不会再发请求,直接从缓存中读取内容,并返回HTTP状态码200


Expires:标头使用明确的时间而不是通过指定经过的时间来指定缓存的生命周期。

Expires: Tue, 28 Feb 2022 22:22:22 GMT

但是时间格式难以解析,也发现了很多实现的错误,有可能通过故意偏移系统时钟来诱发问题;因此,在 HTTP/1.1 中,Cache-Control 采用了 max-age——用于指定经过的时间。 (因为Expires判断强缓存是否过期的机制是:获取本地时间戳,并对先前拿到的资源文件中的Expires字段的时间做比较。来判断是否需要对服务器发起请求。Expires过度依赖本地时间,如果本地与服务器时间不同步,就会出现资源无法被缓存或者资源永远被缓存的情况)


Cache-Controlmax-age=NN就是需要缓存的秒数。从第一次请求资源的时候开始,往后N秒内,资源若再次请求,则直接从磁盘(或内存中读取),不与服务器做任何交互。

Cache-Control: max-age:3600

cache-control中有常见的几个响应属性:

  • max-age例如值为3600,表示(当前时间+3600秒)内不与服务器请求新的数据资源

  • s-maxage和max-age一样,但这个是设定代理服务器的缓存时间(和public共同使用)

  • no-cache表示是强制进行协商缓存(它并不像字面意思一样禁止缓存,实际上,no-cache的意思是强制进行协商缓存。如果某一资源的Cache-control中设置了no-cache,那么该资源会直接跳过强缓存的校验,直接去服务器进行协商缓存。)

  • no-store是表示禁止任何缓存策略

一般请求从客户端直接发送到服务端,但有些情况下是例外的,比如出现代理服务器的时候。而publicprivate就是决定资源是否可以在代理服务器进行缓存的属性。

eg:客户端《===》代理服务器《===》服务器

  • public所有内容都将被缓存(客户端和代理服务器都可缓存)

  • private内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存)

协商缓存

上面的强缓存都是由本地浏览器在确定是否使用缓存,当浏览器没有命中强缓存时就会向浏览器发送请求,验证协商缓存是否命中,如果缓存命中则返回304状态码,否则返回新的资源数据。

协商缓存(也叫对比缓存)是由服务器来确定资源是否可用,这将涉及到两组字段成对出现的,在浏览器第一次发出请求时会带上字段(Last-Modified或者Etag),则后续请求则会带上对于的请求字段(if-modified-since或者if-none-Match),若响应头没有Last-Modified或者Etag,则请求头也不会有对应的字段

  • Last-modified表示本地文件最后修改时间,由服务器返回
  • if-modified-since是浏览器在请求数据时返回的,值是上次浏览器返回的Last-modified
  • ETag是一个文件的唯一标识符,当资源发生变化时这个ETag就会发生变化。弥补了上面last-modified可能出现文件内容没有变化但是last-modified发生了变化出现重新向服务器请求资源情况。这个值也是又服务器返回的
  • if-none-match是浏览器请求数据时带上的字段,值是上次服务器返回的ETag

具体请求流程

  • 当浏览器发起一个资源请求时,浏览器会先判断本地是否有缓存记录,如果没有会向浏览器请求新的资源,并记录服务器返回的last-modified

  • 如果有缓存记录,先判断强缓存是否存在(cache-control优先于expires,后面会说),如果强缓存的时间没有过期则返回本地缓存资源(状态码为200)

  • 如果强缓存失效了,客户端会发起请求进行协商缓存策略,首先服务器判断Etag标识符,如果客户端传来标识符和当前服务器上的标识符是一致的,则返回状态码 304 not modified(不会返回资源内容)

  • 如果没有Etag字段,服务器会对比客户端传过来的if-modified-match,如果这两个值是一致的,此时响应头不会带有last-modified字段(因为资源没有变化,last-modified的值也不会有变化)。客户端304状态码之后读取本地缓存。如果last-modified

  • 如果Etag和服务器端上的不一致,重新获取新的资源,并进行协商缓存返回数据。

ETag作用

它的出现主要是解决last-modified几个比较难以解决的问题

  1. 在没有修改文件内容情况下文件的最后修改时间可能也会改变,这会导致客户端认为这文件被改动了,从而重新请求
  2. 可能有些文件修改比较频繁,秒级以内修改的,If-Modified-Since 能检查到的粒度是秒级的,使用 Etag 就能够保证这种需求下客户端在 1 秒内能刷新多次。
  3. 有些服务器不能精确获取文件的最后修改时间

状态码区别

  • 200 请求成功,服务器返回全新的数据
  • 200 from memory cache / from disk cache 本地强缓存还在有效期,直接使用本地缓存
  • 304 请求成功,走了协商缓存,服务器判定(EtagLast-modified)没有过期,告知浏览器使用缓存

from memory cache 是页面刷新的时候内存取的 from disk cache 页面tab关闭后从磁盘取的

缓存优先级

expirescache-control如果同时存在时,cache-control会覆盖expiresexpires无效,无论是否过期,。即 Cache-control > expires

强缓存和协商缓存如果同时存在时,会去先对比强缓存是否还再有效期,如果强缓存还在有效期内则直接使用强缓存,否则协商缓存生效,即强缓存 > 协商缓存

协商缓存Etaglast-modified同时存在时,会先比较Etaglast-modified无效,即Etag > last-modified

哪些文件对应哪些缓存

有哈希值的文件设置强缓存即可。没有哈希值的文件(比如index.html)设置协商缓存

例如cssjs文件,每次打包之后都会生产一串新的哈希值并追加到我们的文件名中,设置强缓存,不管缓存多久,只要我们重新打包,生产新的哈希值。那么文件名就更改了。对于机器来说,更改了文件名的文件,就是一个新的文件,就会读取新文件。但是一般情况下,index.html是不会设置哈希值