浏览器缓存,304

本文最后更新于:2023年3月19日 晚上

本文转自:https://juejin.im/post/6844903763665240072

浏览器缓存;缓存相关的字段(Etag 与 last-modified 对比区别)

1. 前言

浏览器缓存 是浏览器将用户请求过的静态资源(html、css、js),存储到电脑本地磁盘中,当浏览器再次访问时,就可以直接从本地加载了,不需要再去服务端请求了。
但也不是说缓存没有缺点,如果处理不当,可能会导致服务端代码更新了,但是用户却还是老页面。所以前端们要针对项目中各个资源的实际情况,做出合理的缓存策略。
缓存的优点:

  • 减少了冗余的数据传输,节省网费
  • 减少服务器的负担,提升网站性能
  • 加快了客户端加载网页的速度

2. 缓存流程

这里先介绍一下浏览器缓存资源的一个大概的流程。
我们可以认为,浏览器里有一个专门存放缓存规则的一个数据库,也可以说是一个映射表,把缓存资源信息,同电脑磁盘中的实际文件的地址,对应起来。(大概意思,别较真)

而这个缓存规则的表,在浏览器中是可以看到的: chrome://cache/
不过我升级了浏览器之后,就不好使了,但是找到了 chrome://net-internals/#httpCache ,不知道是不是就是原来的,知道的同学也可以反馈一下

浏览器第一次请求资源时

上面所说的 缓存规则,就是声明所请求的这个资源,要采取哪种缓存策略?缓存多长时间?等等。。。而这个规则,是在 http 的 header 中的返回来的。

注意: 是 response header ,而不是 request header !!!
而实际上, request header 中也会携带规则信息,下面会讲,要区分 request 和 response

3. 缓存规则

强缓存和协商缓存。

强缓存**

简单粗暴,如果资源没过期,就取缓存,如果过期了,则请求服务器。
如何判断资源是否过期呢,也就是说强缓存的规则怎么看?

主要是看 response headers 中的 Cache-Control 的值,图中的 max-age = 31xxxxxxx,就是说在这些秒内,都直接使用缓存,超过了就继续请求服务器
而和 Cache-Control 并列的,还有一个 Expires ,已经基本淘汰了,所以不用管

Cache-Control 的几个取值含义:

**private** 仅浏览器可以缓存
**public** 浏览器和代理服务器都可以缓存(对于 private 和 public,前端可以认为一样,不用深究)
**max-age=xxx** 过期时间(重要)
**no-cache** 不进行强缓存(重要)
**no-store** 不强缓存,也不协商缓存,基本不用,缓存越多才越好呢
注意:规则可以同时多个

所以,对于强缓存,我们主要研究 Cache-Control 中的 max-age 和 no-cache
所以,判断该资源是否命中强缓存,就看 response 中 Cache-Control 的值,如果有 max-age=xxx 秒,则命中强缓存。如果 Cache-Control 的值是 no-cache,说明没命中强缓存,走协商缓存。

强缓存流程


所以强缓存步骤已经很清晰了:

  1. 第一次请求 a.js ,缓存表中没该信息,直接请求后端服务器。
  2. 后端服务器返回了 a.js ,且 http response header 中 cache-control 为 max-age=xxxx,所以是强缓存规则,存入缓存表中。
  3. 第二次请求 a.js ,缓存表中是 max-age, 那么命中强缓存,然后判断是否过期,如果没过期,直接读缓存的 a.js,如果过期了,则执行协商缓存的步骤了。

协商缓存

触发条件:

  1. Cache-Control 的值为 no-cache (不强缓存)
  2. 或者 max-age 过期了 (强缓存,但总有过期的时候)

也就是说,不管怎样,都可能最后要进行协商缓存(no-store 除外)

这个图,虽然强缓存命中,但是也有 ETag 和 Last-Modified ,这两个就是协商缓存的相关规则。虽然之前的强缓存流程和他俩没关。。。
ETag**:每个文件有一个,改动文件了就变了,可以看似 md5
**Last-Modified**:文件的修改时间
也就是说,每次 http 返回来 **response
header 中的 ETag 和 Last-Modified,在下次请求时在 request header 就把这两个带上(但是名字变了 ETag–>If-None-Match,Last-Modified–>If-Modified-Since ),服务端把你带过来的标识,资源目前的标识,进行对比,然后判断资源是否更改了。
这个过程是循环往复的,即缓存表在每次请求成功后都会更新规则。
1. 第 n 次请求成功时:

2. 缓存表中更新该资源的 ETag 值
3. 第 n+1 次请求:
从缓存表中取该资源最新的 ETag,然后加在 request header 中, 注意变名字了,由 ETag – > If-None-Match

图:

所以协商缓存步骤总结:

  1. 请求资源时,把用户本地该资源的 ETag 同时带到服务端,服务端和最新资源做对比。
  2. 如果资源没更改,返回 304,浏览器读取本地缓存。
  3. 如果资源有更改,返回 200,返回最新的资源。

4. 缓存命中显示

1. 从服务器获取新的资源

2. 命中强缓存,且资源没过期,直接读取本地缓存

3. 命中协商缓存,且资源未更改,读取本地缓存


注意:协商缓存无论如果,都要向服务端发请求的,只不过,资源未更改时,返回的只是 header 信息,所以 size 很小;而资源有更改时,还要返回 body 数据,所以 size 会大。

5. 其他

0. 怎么配置资源的缓存规则
可以有后端服务器配置,也可以在 nginx 中配置,稍后会更新一张 nginx 的配置

1. 为什么要有 Etag

你可能会觉得使用 Last-Modified 已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要 Etag 呢?HTTP1.1 中 Etag 的出现(也就是说,ETag 是新增的,为了解决之前只有 If-Modified 的缺点)主要是为了解决几个 Last-Modified 比较难解决的问题:

  • 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新 GET;
  • 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说 1s 内修改了 N 次),If-Modified-Since 能检查到的粒度是 s 级的,这种修改无法判断(或者说 UNIX 记录 MTIME 只能精确到秒);
  • 某些服务器不能精确的得到文件的最后修改时间。

2. 强缓存与协商缓存的区别可以用下表来表示:

3. 用户行为对缓存的影响


即:F5 会 跳过强缓存规则,直接走协商缓存;;;Ctrl+F5 ,跳过所有缓存规则,和第一次请求一样,重新获取资源

6.其他

Expires 和 max-age 的区别

Expires 和 max-age 都可以用来指定文档的过期时间,但是二者有一些细微差别 1.ExpiresHTTP/1.0中已经定义,Cache-Control:max-ageHTTP/1.1中才有定义,为了向下兼容,仅使用 max-age 不够;
2.Expires 指定一个绝对的过期时间(GMT 格式),这么做会导致至少 2 个问题 1)客户端和服务器时间不同步导致 Expires 的配置出现问题 2)很容易在配置后忘记具体的过期时间,导致过期来临出现浪涌现象;
3.max-age 指定的是从文档被访问后的存活时间,这个时间是个相对值(比如:3600s),相对的是文档第一次被请求时服务器记录的 Request_time(请求时间)
4.Expires 指定的时间可以是相对文件的最后访问时间(Atime)或者修改时间(MTime),而 max-age 相对对的是文档的请求时间(Atime) 5.在 Apache 中,max-age 是根据 Expires 的时间来计算出来的 max-age = expires- request_time:(mod_expires.c)

expire 和 etag,last-modified 的优先级问题

转自:https://segmentfault.com/q/1010000022541364
Expires 已经没啥用了,更多的是为了兼容旧浏览器(只支持 HTTP/1.0 的上古时代浏览器)的响应标头。
从 HTTP/1.1 以后就有了 Cache-Control 标头中的 max-age,与上者几乎等效,也就是设值有所不同,前者是设一个具体的时间点、后者是设一个秒数。但显然 Expires 可能因为客户端与服务端时间不一致、或网络延迟导致过期时间不准确,并且 Cache-Control 能设的值更多也就更灵活。
如果两者同时存在,以 Cache-Control 为准。


如果同时设了 ETagLast-Modified,那么必须同时满足条件才会 304,不存在谁更优先就使用谁一说。
但一般分布式环境下(比如 CDN)很少使用 ETag,因为 ETag 依赖 Web Server 的哈希算法,不同 Web Server、不同版本、不同的配置,都会导致同样的文件 ETag 可能是不相等的。当然了,如果你能限制上述信息都一样,也可以使用 ETag,并不绝对。


顺序的话是先判断 Cache-ControlExpires,再 ETag,最后 Last-Modified,都满足就 304,有一项不满足就 200。

max-age  为 0 表示强制检查  Last-ModifiedETag,可以近似理解为与  no-cache  等效。

7. 总结

借两个图


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!