LLwanran / front_end_studying

前端知识要点
https://llwanran.github.io/front_end_studying/
2 stars 1 forks source link

阿里巴巴:浏览器的强缓存和协商缓存(一面) #55

Open LLwanran opened 4 years ago

LLwanran commented 4 years ago

答案:

这里说的缓存是指浏览器(客户端)在本地磁盘中对访问过的资源保存的副本文件。

浏览器缓存主要有以下几个优点:

  1. 减少重复数据请求,避免通过网络再次加载资源,节省流量。
  2. 降低服务器的压力,提升网站性能。
  3. 加快客户端加载网页的速度, 提升用户体验。

浏览器缓存分为强缓存和协商缓存,两者有两个比较明显的区别:

  1. 如果浏览器命中强缓存,则不需要给服务器发请求;而协商缓存最终由服务器来决定是否使用缓存,即客户端与服务器之间存在一次通信。
  2. chrome中强缓存(虽然没有发出真实的http请求)的请求状态码返回是200 (from cache);而协商缓存如果命中走缓存的话,请求的状态码是304 (not modified)。 不同浏览器的策略不同,在Fire Fox中,from cache状态码是 304.

其中 from cache 会分为 from disk cache 和 from memory cache. 从内存中获取最快,但是是 session 级别的缓存,关闭浏览器之后就没有了。
image.png

请求流程

浏览器在第一次请求后缓存资源,再次请求时,会进行下面两个步骤:

  1. 浏览器会获取该缓存资源的header中的信息,根据response header中的expirescache-control来判断是否命中强缓存,如果命中则直接从缓存中获取资源。
  2. 如果没有命中强缓存,浏览器就会发送请求到服务器,这次请求会带上IF-Modified-Since或者IF-None-Match, 它们的值分别是第一次请求返回Last-Modified或者Etag,由服务器来对比这一对字段来判断是否命中。如果命中,则服务器返回 304 状态码,并且不会返回资源内容,浏览器会直接从缓存获取;否则服务器最终会返回资源的实际内容,并更新 header 中的相关缓存字段。

借用网上的一张图片

image.png

强缓存

强缓存是根据返回头中的Expires或者Cache-Control两个字段来控制的,都是表示资源的缓存有效时间。

如果Cache-ControlExpires同时存在的话,Cache-Control的优先级高于Expires

协商缓存

协商缓存是由服务器来确定缓存资源是否可用。 主要涉及到两对属性字段,都是成对出现的,即第一次请求的响应头带上某个字,Last-Modified或者Etag,则后续请求则会带上对应的请求字段If-Modified-Since或者If-None-Match,若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。

HTTP中并没有指定如何生成 ETag,可以由开发者自行生成,哈希是比较理想的选择。

为什么要有 Etag

HTTP1.1Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

优先级

 Cache-Control  > expires > Etag > Last-Modified

用户行为对缓存的影响

~简单说就是 F5 刷新的时候,会暂时禁用强缓存~

经过对qq、fire fox 、safari 、chrome 这几个浏览器的访问同一个页面测试我发现,不同的浏览器在 F5 刷新的时候 ,同一个文件 qq 、fire fox 浏览器会返回304 Not Nodified,在请求头中不携带Expires/Cache-Control; 而 chrome 和 safari 刷新的时候,会返回200 from cache, 没有真正发起请求,走强缓存。可见不同的浏览器反馈是不一致的,所以下面表格中"F5刷新"时Expires/Cache-Control会无效我认为是存在一定争议的。

而 Ctrl + F5 强制刷新的时候,会暂时禁用强缓存和协商缓存。

在写这篇博客时,对于我仅仅测试了一个浏览器之后便写了无效(因为网上大多数帖子写了无效,我也以为我验证通过了),对指出这个问题的群友,表示感谢,希望其他人不会被我误导。

用户操作 Expires/Cache-Control Last-Modied/Etag
地址栏回车 有效 有效
页面链接跳转 有效 有效
新开窗口 有效 有效
前进回退 有效 有效
F5刷新 无效(有争议,不同浏览器反馈不一致) 有效
Ctrl+F5强制刷新 无效 无效

如何设置强缓存和协商缓存

  1. 后端服务器,写入代码逻辑中:

    res.setHeader('max-age': '3600 public')
    res.setHeader(etag: '5c20abbd-e2e8')
    res.setHeader('last-modified': Mon, 24 Dec 2018 09:49:49 GMT)
    
  2. Nginx配置

    add_header Cache-Control "max-age=3600"
    

    一般来说,通过 nginx 静态资源服务器,会默认给资源带上强缓存、协商缓存的 header 字段。

    image.png

两个示例

  1. 如果在cache-control定义的max-age时间之内,js,css文件会走强缓存,http状态码是 200, 跟服务器也并不会有交互。但是第一个文件index.html文件, 每次回车或者刷新都是状态码都是 304 ,因为它的请求头中默认每次都携带了Cache-Control: max-age=0

    image.png

    image.png

  2. js``css文件cache-control超时之后,重新按回车会走协商缓存,请求服务器发现资源没有改变,于是返回 304 ,浏览器从缓存中获取内容,从size中也可以看出端倪, 几百 B 的包不是静态资源的体积。

    image.png

三级缓存原理(大白话)

最后总结一下浏览器的三级缓存原理:

  1. 先去内存看,如果有,直接加载

  2. 如果内存没有,择取硬盘获取,如果有直接加载

  3. 如果硬盘也没有,那么就进行网络请求

  4. 加载到的资源缓存到硬盘和内存

参考文档

from disk cache 与 from memory cache

http协商缓存VS强缓存