Wsh's blog Wsh's blog
首页
  • 基础知识
  • ArkUI
  • UIAbility
  • 组件通信方式
  • 前端缓存
  • React
  • typescript
  • javascript
  • flutter
  • node
  • webpack
web3D😉
宝库📰
  • 分类
  • 标签
  • 归档
龙哥的大🐂之路 (opens new window)
GitHub (opens new window)

wsh

热爱前端的程序媛
首页
  • 基础知识
  • ArkUI
  • UIAbility
  • 组件通信方式
  • 前端缓存
  • React
  • typescript
  • javascript
  • flutter
  • node
  • webpack
web3D😉
宝库📰
  • 分类
  • 标签
  • 归档
龙哥的大🐂之路 (opens new window)
GitHub (opens new window)
  • HTTP概念
  • 强缓存
  • 协商缓存
    • 协商缓存的生效流程
    • last-Modified/ETag
      • 二者区别
    • etag原理和实现
      • 第一种方式:使用文件大小和修改时间
      • 第二种方式:使用文件内容的 hash 值和内容长度。
    • 启发式缓存
    • 浏览器缓存机制
  • 前端应用中的 HTTP 缓存方案
  • Chrome的三种加载方式
  • Memory Cache 和 Disk Cache
  • Service Worker
  • 前端缓存
2022-02-08
目录

协商缓存

二者关系

协商缓存可以看作是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。

浏览器启用协商缓存的前提是强缓存失效,但是反过来强缓存失效并不一定导致浏览器启用协商缓存。

# 协商缓存的生效流程

# last-Modified/ETag

除了强制缓存失效以外,还需要借助服务器响应请求时返回的报头首部:last-modified 和etag(缓存标识)。

etag的优先级要高于last-modified,当两者同时出现时,只有etag会生效,只要有这两个缓存标识之一,在强缓存失效后浏览器便会携带它们向服务器发起请求,携带方式如下所示:

if-modified-since: Wed, 11 May 2022 03:50:47 GMT
if-none-match: "700f049716443285878653598e"
  • if-modified-since: 对应last-modified的值
  • if-none-match: 对应etag的值 服务器根据优先级的缓存标识的值进行判断

如果 eTag 对应的 if-none-match 不存在,那么服务器会将 last-modified 对应的 if-modified-since 的时间值与服务器该资源的最后修改时间进行对比,最后判断是否走协商缓存。

# 二者区别

  • 精确度: last-modified是一个时间,单位最小为秒,如果资源修改快到毫秒级别,服务器会任务该资源没有更新,导致资源在浏览器没有及时更新。

  • 性能上:Etag要逊于Last-Modified,因为Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。

  • 优先级上,服务器校验优先考虑Etag

# etag原理和实现

node下的etag (opens new window)为例:

# 第一种方式:使用文件大小和修改时间

图中当判断所要处理的内容是文件 stats 对象时,将会采用上述方法生成 eTag 值,最后返回的值是由文件大小和文件最后一次修改时间组成的字符串。

/**
 * Generate a tag for a stat.
 *
 * @param {object} stat
 * @return {string}
 * @private
 */

function stattag (stat) {
  var mtime = stat.mtime.getTime().toString(16)
  var size = stat.size.toString(16)

  return '"' + size + '-' + mtime + '"'
}

# 第二种方式:使用文件内容的 hash 值和内容长度。

/**
 * Generate an entity tag.
 *
 * @param {Buffer|string} entity
 * @return {string}
 * @private
 */

function entitytag (entity) {
  if (entity.length === 0) {
    // fast-path empty
    return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"'
  }

  // compute hash of entity
  var hash = crypto
    .createHash('sha1')
    .update(entity, 'utf8')
    .digest('base64')
    .substring(0, 27)

  // compute length of entity
  var len = typeof entity === 'string'
    ? Buffer.byteLength(entity, 'utf8')
    : entity.length

  return '"' + len.toString(16) + '-' + hash + '"'
}

通过对内容的 hash 转化和截取,最终返回内容长度与其 hash 值组合成的字符串。

通过上述方法生成的 eTag 也被称为强 eTag 值,其不论实体发生多么细微的变化都会改变它的值。那么与其对立的便是弱 eTag 值,在 eTag 包源码中我们可以发现通过传递第二个参数 weak 值为 true 时便可启用弱校验。

function etag (entity, options) {
  if (entity == null) {
    throw new TypeError('argument entity is required')
  }

  // support fs.Stats object
  var isStats = isstats(entity)
  var weak = options && typeof options.weak === 'boolean'
    ? options.weak
    : isStats

  // validate argument
  if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) {
    throw new TypeError('argument entity must be string, Buffer, or fs.Stats')
  }

  // generate entity tag
  var tag = isStats
    ? stattag(entity)
    : entitytag(entity)

  return weak
    ? 'W/' + tag
    : tag
}

弱 ETag

弱 ETag 值只适用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变 ETag 值。这时会在字段值最开始处附加 W/。

ETag: W/"29322-09SpAhH3nXWd8KIVqB10hSSz66"

# 启发式缓存

强缓存新鲜度的公式为:缓存新鲜度 = max-age || (expires - date)。响应报头中没有 max-age(s-maxage) 和 expires 这两个关键的字段值,浏览器还是会走强缓存

date: Thu, 02 Sep 2021 13:28:56 GMT
age: 10467792
cache-control: public
last-modified: Mon, 26 Apr 2021 09:56:06 GMT

虽然有与协商缓存相关的 last-modified 首部,但并不会走协商缓存,反而浏览器会触发启发式缓存。启发式缓存对于缓存新鲜度计算公式如下所示:

缓存新鲜度 = max(0,(date - last-modified)) * 10%

根据响应报头中 date 与 last-modified 值之差与 0 取最大值后取其值的百分之十作为缓存时间。

# 浏览器缓存机制

#cache
强缓存
前端应用中的 HTTP 缓存方案

← 强缓存 前端应用中的 HTTP 缓存方案→

最近更新
01
组件通信方式
01-07
02
UIAbility
01-07
03
ATKTS
01-06
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Wsh | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式