# HTTP缓存

合理的请求缓存能优化性能! 缓存分为强缓存和协商缓存

# 浏览器缓存位置

  • Service Worker

让 JS 运行在主线程之外,脱离了浏览器的窗体,常见的有离线缓存消息推送网络代理

  • Memory Cache

内存缓存,效率最快,但是存活时间短,当渲染进程结束后,内存缓存就不存在了。

  • Disk Cache

磁盘缓存,存取效率比内存缓存慢,存活时间长、存储容量大。

比较大的JS、CSS文件会存到磁盘,反之在内存;内存使用率较高的时候,文件优先进入磁盘。

  • Push Cache

推送缓存,HTTP/2的内容。

# 强缓存

不需要发送HTTP请求,通过检查相应的字段判断,HTTP/1.0使用的是Expires,HTTP/1.1使用的是Cache-Control。

  • Expires

即过期时间,存在于服务端返回的响应头中,告诉浏览器在这个过期时间之前可以直接从缓存里面获取数据,无需再次请求

Expires: Wed, 07 Apr 2021 01:21:20 GMT
1

表示资源在2021年4月7日01:21:20过期,过期了就需要向服务端发请求。

存在的问题:浏览器和服务器的时间不一致,因此时间就可能不准确。

  • Cache-Control

Cache-Control采用过期时长控制缓存,对应的是max-age

Cache-Control: max-age=3600
1

表示响应在3600秒后失效,也就是一个小时内都可以使用缓存。

max-age还有其他属性

public: 客户端和代理服务器都可以缓存
private: 只有浏览器能缓存,中间的代理服务器不能缓存
no-cache: 跳过当前的强缓存,发送HTTP请求,即直接进入协商缓存阶段
no-store: 不进行任何形式的缓存
s-maxage: 类似max-age,但是这个是针对代理服务器的缓存时间
must-revalidate: 一旦缓存过期,必须回到资源服务器验证
1
2
3
4
5
6
  • 注意

当Expires和Cache-Control同时存在的时候,Cache-Control会优先考虑。
强缓存失效了,就会进入协商缓存。

# 协商缓存

强缓存失效之后,浏览器在请求头中携带相应的缓存tag来向服务器发请求,由服务器根据这个tag,来决定是否使用缓存。

  • Last-Modified

即最后修改时间,在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段。 浏览器接收到后,如果再次请求,会在请求头中携带If-Modified-Since字段,这个字段的值也就是服务器传来的最后修改时间。

服务器拿到请求头中的If-Modified-Since的字段后,会跟这个服务器中该资源的最后修改时间对比:

  1. 如果请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
  2. 否则返回304,告诉浏览器直接用缓存。
  • ETag

服务器给当前文件的内容的唯一标识,只有内容变动,ETag才会变。 浏览器接收到ETag的值,会在下次请求时,将这个值作为If-None-Match这个字段的内容,并放到请求头中,然后发给服务器。

服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行对比:

  1. 如果两者不一样,说明要更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
  2. 否则返回304,告诉浏览器直接用缓存。
  • 注意
  1. 在精准度上,ETag优于Last-ModifiedETag 是按照内容给资源上标识,因此能准确感知资源的变化。而 Last-Modified 就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况:
1. 编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。
2. Last-Modified 能够感知的单位时间是秒, 如果文件在 1 秒内改变了多次,
那么这时候的 Last-Modified 并没有体现出修改。
1
2
3
  1. 在性能上,Last-Modified优于ETag,也很简单理解,Last-Modified仅仅只是记录一个时间点,而 ETag需要根据文件的具体内容生成哈希值。

  2. 如果两种方式都支持的话,服务器会优先考虑ETag