@
silenceeeee 我认为你的理解有误,01.jpg 均被 Chrome、Safari 和 Firefox 缓存,造成响应的不同在于浏览器对刷新操作的不同实现。下面详细说说我的看法。
1. 响应被缓存储存的条件
(引用标准 RFC7234,原文见
https://tools.ietf.org/html/rfc7234#section-3 )
HTTP 缓存要求的重点是防止缓存存储不可复用的响应,或者不恰当地复用已存储的响应,而不是批准缓存总是存储和复用特定的响应。
存储条件:
- 请求方法可被缓存且被缓存理解;
- 响应状态码被缓存理解;
- no-store 缓存指令不在请求或响应中;
- 如果是共享缓存:private 指令不在响应中, Authorization 字段不在请求中 (除非响应明确允许,如使用 public 指令)
- 符合以下情况之一:Expires、max-age、共享缓存和 s-maxage、可被缓存的状态码、public、允许缓存的 Cache Control 扩展
按条件分析:请求方法 GET、200 响应(可被缓存),没有其它指令,所以根据标准,该响应可被储存。
实际上,从刷新后的 200 from memory cache、304 这两状态码来看,01.jpg 已经被缓存,只不过 Chrome 是命中了已储存的 200 响应,而 Safari 和 Firefox 是经条件请求对已储存的 200 响应验证成功后返回了 304 响应。
2. Cache-Control 没有默认值
https://stackoverflow.com/questions/14496694/whats-default-value-of-cache-control如果服务器端没有设置 Cache-Control 字段,那么响应里自然没有。
3. 关于 from memory cache 和 304 响应( RFC7234 )
响应被缓存储存后,优先复用该响应来满足未来的等效请求。
RFC 中的复用条件:
- effective request URI 和 selecting header 均匹配
- 与已存储的响应相关联的请求方法允许该响应用于出现的请求;
- 请求和响应中均没有 no-cache,除非成功验证已存储的响应
- 已存储的响应是以下情况之一:新鲜的、被成功验证的、允许作为陈旧响应来提供
如果上述条件均满足,而且是新鲜的响应,那将复用缓存里的相应响应,这将导致 from memory cache (状态码为相应响应的)。
如果响应过期,那么将发送带 ETag 中验证器的条件请求到服务器,验证响应有没有发生变化,如果没有变化,将返回 304 (Not Modified) 响应。
4. 响应的过期判断( RFC7234 )
源服务器一般会为响应分配未来的显式过期时间, 通过 s-maxage、max-age、Expires 这几种方式,并根据一定的算法计算当前响应的 age (大概为 now - Date ),如果 age > max-age,则该已储存的响应已经过期,通常需要验证才能复用。
具体到你的例子,由于你没有提供显式过期时间,浏览器将使用启发式的算法计算过期时间(通常算法为 (date_value - last_modified_value) / 10 ),上面 @
morethansean 也提到了。
现代浏览器的算法应该都差不多,所以应该不是 Chrome 计算认为已存储的响应没有过期,而 Safari 和 Firefox 计算认为已经过期,必须验证。
5. 关于浏览器对刷新操作的实现
https://juejin.im/entry/58b82f602f301e006c545b05通常刷新 (F5) 会强制验证已储存的响应,如果验证成功,返回 304 响应,如例子 Safari 和 Firefox 的行为。
而 Chrome 改变了刷新按钮的重新验证机制,仅验证主要资源,而子资源直接从缓存中读取。这就是对 01.jpg 的请求返回 200 from memory cache 的原因。