前端http请求细节——Cache-Control(缓存机制)

Cache-Control 通用消息头字段,被用于在 http 请求和响应中,通过指定指令来实现缓存机制。缓存指令是单向的,这意味着在请求中设置的指令,不一定被包含在响应中。

请求和响应中的 Cache-Control 指令并不完全相同,具体可以查看这里,包括指令的具体意思,这里不过多赘述。(默认值:private)

缓存

浏览器的缓存机制是根据 HTTP 报文的缓存标识进行的,浏览器第一次向服务器发起该请求后拿到请求结果,会根据响应报文中 HTTP 头的缓存标识,决定是否缓存结果。
浏览器缓存策略分为两种:强制缓存和协商缓存。

  • 强制缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程。
  • 协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。
强制缓存(存储位置)

强制缓存不会向服务器发送请求,直接从缓存中读取资源,可以看到请求返回的状态码都是200,并且 Size 代表该缓存的位置。

浏览器读取缓存的顺序为memory –> disk。

  • 内存缓存(memory cache):
    快速读取:内存缓存会将编译解析后的文件,直接存入该进程的内存中,占据该进程一定的内存资源,以方便下次运行使用时的快速读取。
    时效性:一旦该进程关闭,则该进程的内存则会清空。

  • 硬盘缓存(disk cache):
    硬盘缓存则是直接将缓存写入硬盘文件中,读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢。

三级缓存原理 (访问缓存优先级):

  1. 先在内存中查找,如果有,直接加载。
  2. 如果内存中不存在,则在硬盘中查找,如果有直接加载。
  3. 如果硬盘中也没有,那么就进行网络请求。
  4. 请求获取的资源缓存到硬盘和内存。

在浏览器中,浏览器会在js,字体,图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。

为什么CSS会放在硬盘缓存中?
因为CSS文件加载一次就可渲染出来,我们不会频繁读取它,所以它不适合缓存到内存中,但是js之类的脚本却随时可能会执行,如果脚本在磁盘当中,我们在执行脚本的时候需要从磁盘取到内存中来,这样IO开销就很大了,有可能导致浏览器失去响应。

协商缓存(判断资源是否更新的验证机制)
  • Last-Modified / If-Modified-Since
    Last-Modified 是服务器响应请求时,返回 response header 该资源文件在服务器最后被修改的时间。
    If-Modified-Since 则是客户端再次发起该请求时,request header 携带上次请求返回的Last-Modified值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。

若服务器的资源最后被修改时间 > If-Modified-Since的字段值
则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件

  • Etag / If-None-Match
    Etag 是服务器响应请求时,返回 response header 当前资源文件的一个唯一标识(由服务器生成)。
    If-None-Match是客户端再次发起该请求时,request header 携带上次请求返回的唯一标识Etag值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。

If-None-Match 的字段值 = 该资源在服务器的Etag值
一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200。

ETag 和 Last-Modified 区别

  • 在方式上,Etag是对资源的一种唯一标识,而Last-Modified是该资源文件最后一次更改时间
  • 在精确度上,Etag要优于Last-Modified。Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;如果是负载均衡的服务器,各个服务器生成的Last-Modified也有可能不一致。
  • 在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。
  • 在优先级上,服务器校验优先考虑Etag。
其他:
  • Pragma 是一个在 HTTP/1.0 中规定的通用首部。(Pragma 唯一指令 no-cache 与 Cache-Control: no-cache 效果一致)
    在 HTTP 响应中的行为没有确切规范且在 HTTP/1.1 协议中的 Cache-Control 出现前,所以仅作为与 http 的向后兼容而定义,建议只在需要兼容 HTTP/1.0 客户端的场合下应用 Pragma 首部。
  • Expires是HTTP/1.0控制网页缓存的字段,其值为服务器返回该请求结果缓存的到期时间,即再次发起该请求时,如果客户端的时间小于Expires的值时,直接使用缓存结果。
    到了HTTP/1.1,Expire已经被Cache-Control替代,原因在于Expires控制缓存的原理是使用客户端的时间与服务端返回的时间做对比,那么如果客户端与服务端的时间因为某些原因(例如时区不同;客户端和服务端有一方的时间不准确)发生误差,那么强制缓存则会直接失效,这样的话强制缓存的存在则毫无意义。

参考链接:
https://juejin.im/entry/5ad86c16f265da505a77dca4
https://www.cnblogs.com/suihang/p/12855345.html
https://www.jianshu.com/p/54cc04190252

你可能感兴趣的:(前端http请求细节——Cache-Control(缓存机制))