Gahing's blog Gahing's blog
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Gahing / francecil

To be best
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • AIGC

  • Git

  • Linux

  • 数据协议

  • 数据结构

  • 架构设计

  • 算法

  • 编程工具

  • 编程范式

  • 编解码

  • 网络基础

    • HTTP状态码
    • CDN
    • DNS
    • HTTP
    • TCP
    • Web安全
    • http2
    • https
    • websocket
    • 跨域
    • cookie
    • 如何减少预检请求OPTIONS
    • 浏览器缓存
      • 前言
      • 查看缓存文件
      • 强缓存
        • Cache-Control 响应头
        • max-age
        • s-maxage
        • no-cache
        • no-store
        • public
        • private
        • stale-while-revalidate
        • Expires 响应头
      • 协商缓存
        • Last-modified 响应头
        • ETag 响应头
      • 总流程
      • 用户行为
      • 常见问题
        • 请求头出现 Provisional headers are shown 的原因
        • 响应头未设置 cache-control 和 expires 还会命中强缓存么?
        • 如何设置才能不缓存资源
        • 通过 Expires 判断缓存过期,而本地时间比服务器时间快的话,会出现什么问题?
      • 浏览器缓存中的其他缓存
      • 参考
  • 通用技术
  • 网络基础
gahing
2019/12/29
目录

浏览器缓存

# 前言

Web 缓存分为浏览器缓存和服务端缓存,本文主要描述的是浏览器缓存中的 HTTP 缓存

# 查看缓存文件

chrome 可以通过 chrome://view-http-cache 查看浏览器的缓存文件

chrome 66 后就用不了了

pc 上的实际存储位置

\User\{user}\AppData\Local\google\Chrome\User Data\Default\Cache\index 的文件内容
1

火狐可以通过 about:cache 查看缓存文件列表

进入缓存文件详情页,可以看到缓存文件内容由三部分组成

  • 资源请求地址
  • 响应头
  • 原文件的二进制内容

而实际的缓存文件也是包含这些部分的,我们可以通过 ChromeCacheView 工具查看内部内容

通过下面几个问题来学习 pc 上浏览器缓存如何设计的

  • 是不是应该有一个列表文件记录所有缓存文件的基本信息?

  • 不能直接拿到缓存源文件,每次命中缓存都需要解码文件?

  • 从如果删了缓存文件,是删了什么东西?列表文件内容会相应的修改不?

  • 不会出现列表文件内容还在但是对应缓存原文件被删除的情况?

TODO

# 强缓存

# Cache-Control 响应头

优先级比 Expires 高,且用的是相对时间,不需要担心客户端与服务端时间不一致带来的缓存失效问题

# max-age

指定缓存的有效期

# s-maxage

指定代理缓存(如cdn缓存)的有效期,优先级比 max-age 高

# no-cache

不使用本地缓存和代理缓存

# no-store

禁用缓存

# public

可以被所有用户缓存,包括终端用户以及 CDN 等中间代理服务器

默认值

# private

仅能被终端用户缓存

# stale-while-revalidate

  1. 非缓存标准,属于缓存拓展,实验性质,仅部分浏览器可用。
  2. 和 max-age 配合使用。若 max-age 过期,而 stale-while-revalidate 还在有效期内,仅继续使用强缓存,并额外发送一个请求去刷新缓存;而如果 stale-while-revalidate 也过期,则正常重新刷新。

举例:max-age=60, stale-while-revalidate=10;

  • 在 60s 内访问请求都将命中强缓存
  • 在 60~70s 内访问请求,先使用强缓存,并额外请求一次去更新缓存(包括有效期)
  • 60~70s内有请求的情况下,在 80s 时请求,将命中强缓存
  • 60~70s内没有请求的情况下,在 80s 时请求,无缓存可用,发起新的请求

实际可用的场景较少,了解就好。大部分需求场景可以通过 js 解决,参考 js 的 swr 库,其实就是利用了 stale-while-revalidate 的思想。

更多资料详见:

  • 使用 stale-while-revalidate 保持新鲜度 - web.dev (opens new window)

# Expires 响应头

表示资源过期时间,以服务端时间为准

# 协商缓存

# Last-modified 响应头

表示服务端文件的最后修改时间

当缓存过期时,再次发起请求,会带个 If-Modified-Since 请求头,其值为之前返回的 Last-modified 响应头的值

服务端会去查询在该时间点后文件是否被修改,若被修改,返回新的资源, 200 响应以及 Last-modified 的新值;否则返回 304 响应,根据 Cache-Control 或 Expires 重新设置过期时间

# ETag 响应头

由于 Last-modified 只精确到秒,且如果内容没变但是最后修改时间变了,还是会当新资源请求

于是 http1.1 加了一个 ETag 响应头

其值为根据文件内容生成的 hash

当缓存过期时,再次发起请求,会带上 If-None-Match 请求头,其值为之前返回的 ETag 响应头的值

服务器会去该值和服务器文件的 hash 进行比对,若不同,返回新的资源和 200 响应以及 ETag 的新值;否则返回 304 响应,根据 Cache-Control 或 Expires 重新设置过期时间

优先级比 Last-modified 高

当两个同时存在时,先判断 ETag ,如果 hash 值没有变化,再去判断 Last-modified ,最终决定是否返回 304

# 总流程

借用 [浅谈 Web 缓存] 中的图

alloyteam

# 用户行为

用户操作 强缓存 协商缓存
前进后退 有效 有效
地址栏回车 ? 有效
按刷新按钮 无效 有效
F5 无效 有效
ctrl + F5 无效 无效
Disable cache 无效 无效

前四种针对的是文档请求,后两者针对的是所有资源的请求

强缓存失效的原因在于浏览器会在请求中带上cache-control: max-age=0

协商缓存失效的原因在于本该带上 If-Modified-Since 或 If-None-Match 请求头,但是浏览器没有带上,并带上以下两个请求头避免强缓存,因此会重新加载资源

Cache-Control: no-cache
Pragma: no-cache
1
2

前进后退是浏览器直接拿缓存页面,即使强缓存已经过期,所以即使断网了,后退还是能访问原来页面文档,参考自:https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.13

会发现此时网络请求头显示 Provisional headers are shown

地址栏回车之所以不固定,在于当前文档链接与要回车的链接是否相同。如果相同,浏览器会认为这是打算 f5 刷新,强缓存无效,否则强缓存有效

最后两种的区别在于,前者会走内存缓存(相同请求命中内存缓存,不会再发一条请求),后者什么缓存都不走;

放入内存缓存的是页面扫描加载的,脚步异步请求的不放内存中(没做完整的测试,不确定)

# 常见问题

# 请求头出现 Provisional headers are shown 的原因

  1. 插件拦截
  2. 命中本地缓存
  3. 服务器超时
  4. 跨域拦截,最经常出现的情况,非同源的资源请求都会显示这个

# 响应头未设置 cache-control 和 expires 还会命中强缓存么?

对于前进后退的场景来说,有没有这些响应头,都会命中强缓存

其他场景则不会命中

# 如何设置才能不缓存资源

# 通过 Expires 判断缓存过期,而本地时间比服务器时间快的话,会出现什么问题?

如果通过 Expires 判断缓存过期,而本地时间又比服务端快资源有效期以上,就会出现始终不能命中强缓存的情况

# 浏览器缓存中的其他缓存

读取某个 url 的资源,按照下面的过程

(需要做个试验)

内存缓存

preload 预加载的资源会存储在此处 当前页面已经加载过的资源会放在内存中,方便读取 但注意一点,如果资源设置了 no-store ,前面即使加载过这个资源,还是会继续加载(待确定)

Service Worker 缓存

有一套自己的缓存API,更加可控,不受浏览器影响

HTTP 缓存

上文提到的那个,根据请求响应等头部信息确定是否走缓存

HTTP2 Push 缓存

有一定的时效,chromium 中是五分钟 在命中缓存后,可能会在 HTTP 缓存中增加拷贝以及内存缓存增加引用

# 参考

  1. 浅谈 Web 缓存 (opens new window)
  2. http协商缓存VS强缓存 (opens new window)
  3. Cache-Control (opens new window)
  4. 【译】关于四种缓存的故事 (opens new window)
编辑 (opens new window)
#缓存
上次更新: 2024/09/01, 23:56:56
如何减少预检请求OPTIONS

← 如何减少预检请求OPTIONS

最近更新
01
浅谈代码质量与量化指标
08-27
02
快速理解 JS 装饰器
08-26
03
Vue 项目中的 data-v-xxx 是怎么生成的
09-19
更多文章>
Theme by Vdoing | Copyright © 2016-2024 Gahing | 闽ICP备19024221号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式