Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP 缓存 #18

Open
yeojongki opened this issue Jul 24, 2019 · 0 comments
Open

HTTP 缓存 #18

yeojongki opened this issue Jul 24, 2019 · 0 comments
Labels

Comments

@yeojongki
Copy link
Owner

yeojongki commented Jul 24, 2019

HTTP 缓存

转载:https://zhuanlan.zhihu.com/p/44789005 (有删改)

补充:流程图

image

1. 按缓存位置分类

我们可以在 Chrome 的开发者工具中,Network -> Size 一列看到一个请求最终的处理方式:如果是大小 (多少 K, 多少 M 等) 就表示是网络请求,否则会列出 from memory cache, from disk cachefrom ServiceWorker

它们的优先级是:(由上到下寻找,找到即返回;找不到则继续)

  1. Service Worker
  2. Memory Cache
  3. Disk Cache
  4. 网络请求

1.1 memory cache

memory cache 是内存中的缓存,几乎所有的网络请求资源都会被浏览器自动加入到 memory cache 中。但是也正因为数量很大但是浏览器占用的内存不能无限扩大这样两个因素,memory cache 注定只能是个“短期存储”。常规情况下,浏览器的 TAB 关闭后该次浏览的 memory cache 便告失效 (为了给其他 TAB 腾出位置)。而如果极端情况下 (例如一个页面的缓存就占用了超级多的内存),那可能在 TAB 没关闭之前,排在前面的缓存就已经失效了。

刚才提过,几乎所有的请求资源 都能进入 memory cache

memory cache 机制保证了一个页面中如果有两个相同的请求 (例如两个 src 相同的 ,两个 href 相同的 ) 都实际只会被请求最多一次,避免浪费。

不过在匹配缓存时,除了匹配完全相同的 URL 之外,还会比对他们的类型,CORS 中的域名规则等。因此一个作为脚本 (script) 类型被缓存的资源是不能用在图片 (image) 类型的请求中的,即便他们 src 相等。

在从 memory cache 获取缓存内容时,浏览器会忽视例如 max-age=0, no-cache 等头部配置。例如页面上存在几个相同 src 的图片,即便它们可能被设置为不缓存,但依然会从 memory cache 中读取。这是因为 memory cache 只是短期使用,大部分情况生命周期只有一次浏览而已。而 max-age=0 在语义上普遍被解读为“不要在下次浏览时使用”,所以和 memory cache 并不冲突。

但如果是不想让一个资源进入缓存,就连短期也不行,那就需要使用 no-store。存在这个头部配置的话,即便是 memory cache 也不会存储,自然也不会从中读取了。

1.2 disk cache

disk cache 也叫 HTTP cache,顾名思义是存储在硬盘上的缓存,因此它是持久存储的,是实际存在于文件系统中的。而且它允许相同的资源在跨会话,甚至跨站点的情况下使用,例如两个站点都使用了同一张图片。

disk cache 会严格根据 HTTP 头信息中的各类字段来判定哪些资源可以缓存,哪些资源不可以缓存;哪些资源是仍然可用的,哪些资源是过时需要重新请求的。当命中缓存之后,浏览器会从硬盘中读取资源,虽然比起从内存中读取慢了一些,但比起网络请求还是快了不少的。绝大部分的缓存都来自 disk cache

2. 按失效策略分类

2.1 强缓存

实现强缓存可以通过两种响应头实现:ExpiresCache-Control。强缓存表示在缓存期间不需要请求,state code200

Expires: Tue, Jul 23 2019 19:15:42 GMT

Expires 出现于 HTTP / 1.0 。表示资源会在 Tue, Jul 23 2019 19:15:42 GMT 后过期,在未过期之前不需要再次请求。并且 Expires 受限于本地时间,如果修改了本地时间,会导致浏览器判断缓存失效。

Cache-Control: public, max-age=86400

Cache-Control 出现于 HTTP / 1.1,优先级高于 Expires 。该属性表示资源会在 86400 秒(一天)后过期,在该时间内再次访问该资源,均使用本地的缓存,不再向服务器发起请求。

下面列举一些 Cache-control 字段常用的值:(完整的列表可以查看 MDN)

  • max-age:即最大有效时间,在上面的例子中我们可以看到
  • must-revalidate:如果超过了 max-age 的时间,浏览器必须向服务器发送请求,验证资源是否还有效。
  • no-cache:虽然字面意思是“不要缓存”,但实际上还是要求客户端缓存内容的,只是是否使用这个内容由后续的对比来决定。
  • no-store: 真正意义上的“不要缓存”。所有内容都不走缓存,包括强制和对比。
  • public:所有的内容都可以被缓存 (包括客户端和代理服务器, 如 CDN)
  • private:所有的内容只有客户端才可以缓存,代理服务器不能缓存。默认值。

这些值可以混合使用,例如 Cache-control:public, max-age=2592000

2.2 协商缓存

当强制缓存失效(超过规定时间)时,就需要使用对比缓存,需要询问原始服务器是否发生变化。整体流程如下:

  • 第一次请求:如一个 js 文件,服务器响应头可能会返回以下字段,浏览器会将这些信息缓存到本地。

    • Expires (过期时间)
    • Cache-Control (缓存控制)
    • ETag (资源标识符)
    • Last-Modified (资源最后被修改的时间)
  • 第二次请求:

    • 浏览器的处理:检查 Expires / Cache-Control,这里假设存在之一。

      • 向服务器发送请求,并在请求头中发送两个字段 If-Modified-SinceIf-None-Match (第一次请求中缓存的值),此时服务器会进行比对。
        • 如未失效,则返回 HTTP 状态码 304 表示继续使用,于是客户端继续使用缓存
        • 失效则服务器会返回新的数据和缓存规则,再重新执行一遍流程
    • 服务器的处理:

      • 通过字段 Last-Modified / Etag 告知客户端。(注:两个字段会被浏览器储存,浏览器的处理中发出的字段 If-Modified-Since / If-None-Match 就是该值)

      • 进行对比,有两种方式

        • Last-Modified & If-Modified-Since:将它们的值进行对比,如果相同,则表示该文件未被修改,响应 304。反之则表示文件已经修改,响应 200 状态码。这种方式有一定的缺陷:

          • 如果资源更新的速度是秒以下单位,那么该缓存是不能被使用的,因为它的时间单位最低是秒
          • 如果文件周期性更新,尽管文件可能没有变化,但是修改时间永远是生成的时间,所以起不到缓存的作用
          • 被修改的信息并不重要,如注释,此时不希望缓存更新

          为了解决以上问题,出现了第二种方式:

        • Etag & If-None-Match:同上对比它们的值。(注:Etag 存储的是文件的特殊标识(一般都是 hash 生成的),服务器存储着文件的 Etag 字段。)

附上:服务器demo

@yeojongki yeojongki added the HTTP label Jul 24, 2019
@yeojongki yeojongki changed the title http 缓存 HTTP 缓存 Jul 24, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant