关于javascript:浏览器缓存RFC7234

10次阅读

共计 8420 个字符,预计需要花费 22 分钟才能阅读完成。

http 缓存

译注:本文翻译自:https://www.rfc-editor.org/rf…
非英语专业,仅作参考应用。如果英语不错的倡议看原文。
文中许多概念是直译的,可能不太好了解,能够浏览对于浏览器缓存的总结。

1、概述

HTTP 通常用于能够通过应用响应缓存来进步性能的分布式信息系统。本文档定义了 HTTP / 1.1 中缓存和重用响应音讯相干的内容

HTTP 缓存是响应音讯的本地存储并且也是管制存储,检索和删除音讯的子系统。缓存存储可缓存的响应,以缩小将来等效申请的响应工夫和网络带宽耗费。除了隧道服务器,任何客户端或服务器都能够应用缓存

共享缓存是一种被多位用户重用的存储响应。共享缓存通常(但并不总是)作为传输媒介(intermediary)的一部分。
相同,公有缓存,则专门用于同一用户(single user),他们通常被部署为用户代理组件

HTTP / 1.1 缓存的指标是通过重用先前的响应音讯以满足以后申请,来显着进步性能。如果响应能够在没有“验证”的状况下重用,那么每次重用时都会缩小提早和网络开销。当缓存的响应不够新(fresh)时,如果能够通过验证(第 4.3 节)或起源无奈响应时(unavilable)(第 4.2.4 节),依然能够重复使用


2、缓存操作概述

失当的缓存操作保留 HTTP 传输的语义([RFC7231]),同时防止对缓存中已存在的信息进行传输。尽管缓存是 HTTP 的齐全可选性能,然而能够假如重用缓存的响应是可取的,
在没有规定或本地配置要求时,这种重用是默认行为。因而,HTTP 缓存标准的重点在于阻止缓存存储不可复用的响应或者不失当的响应,而非总是存储缓存或者重用特定响应

每条缓存记录由缓存键和与应用雷同键的先前申请绝对应的一个或多个 HTTP 响应组成。最常见的缓存记录是检索申请的胜利后果。换言之,就是一个响应为 200,并蕴含被申请指标进行资源标示形容的 GET 申请。([RFC7231]第 4.3.1 节))。不过,也能够缓存永恒重定向,否定后果(例如,404(Not Found)),不残缺的后果(例如,206(Partial Content)),并且除了 GET 以外也蕴含,明确容许此类缓存且定义了能够用作缓存键值的响应办法

主缓存键由申请办法和指标 URI 组成。然而,因为现在通常应用的 HTTP 缓存通常限度于 GET 响应缓存,因而许多缓存只需回绝其余办法并仅应用 URI 作为主缓存键

如果申请指标受内容协商影响,则其缓存记录可能蕴含多个响应存储内容,每个存储响应由原始申请抉择题目字段的值作为辅助密钥来进行辨别(第 4.1 节)


3、在缓存中存储响应

除了以下状况,缓存不应该存储任何申请的响应:
缓存能够了解申请办法,并将其定义为可缓存的,且
缓存中了解响应状态代码,以及
在申请或者响应的字段中没有显示的指出 ”no-store” 缓存指令(请参阅第 5.2 节)
如果缓存是共享的,则“private”响应指令(参见第 5.2.2.6 节)不应呈现在响应中。
除非响应明确容许(参见第 3.2 节),否则,共享缓存不应该呈现 Authorization 字段(参见 [RFC7235] 的第 4.2 节),以及
响应应满足
蕴含 Expires 头部字段(参见第 5.3 节),或
蕴含 max-age 响应指令(参见第 5.2.2.8 节),或
蕴含 s -maxage 响应指令(参见第 5.2.2.9 节),用于共享缓存,或者
蕴含容许对其进行缓存的“Cache Control Extension”(请参阅第 5.2.3 节),或
具备默认可缓存的状态代码(参见第 4.2.2 节),或
蕴含 public 响应指令(参见第 5.2.2.5 节)
请留神,下面列出的任何要求都能够被缓存管制扩大笼罩; 见第 5.2.3 节
在此上下文中,缓存能够辨认已确认实现了缓存相干行为的申请办法或者响应状态码
留神,在通常状况下如果既没有缓存验证,也没有明确过期工夫的有效响应存储将不会被缓存。不过缓存也不会禁止这样的响应存储

3.1 存储不残缺响应

在连贯被敞开时,当所有被音讯帧被标记为承受,那么这个响应音讯被认为是残缺的(RFC7230)。如果一个申请办法是 GET,响应状态码为 200(OK),并且已接管到整个响应标头局部,如果缓存条目被记录为不残缺,则缓存能够存储不残缺的响应音讯注释。同样地,能够存储 206(Partial Content)响应,作为是不残缺的 200(OK)缓存条目。然而,如果它不反对 Range 和 Content-Range 字段,或者它不理解这些字段中应用的范畴单位,那么缓存就不能存储不残缺或局部内容响应,

缓存能够通过应用子申请分段申请并且应用存储记录来组合胜利响应使得响应申请残缺(在 3.3 局部进行定义)。缓存不应该应用不残缺的响应申请,除非该响应曾经被组合残缺或者该申请为一个指明了残缺响应范畴内的局部响应。在没有明确标记应用如 206(Partial Content)状态码的状况下,缓存不应该发送局部响应给客户端。

3.2 存储 Authenticated 申请的响应

除非响应中存在存储首部字段,否则共享缓存不应该对蕴含 Authorization 首部字段的申请应用缓存响应
在本阐明中,Cache-Control 响应指令(第 5.2.2 节)应含有:must-revalidate,public 和 s -maxage。
须要留神的是,蕴含“must-revalidate”和 / 或“s-maxage”响应指令的缓存响应不容许共享缓存应用古老的响应(第 4.2.4 节)。须要特地指出的是,响应蕴含 ”max-age=0, must-revalidate” 或者 ”s-maxage=0″,在没有在源服务器上从新验证的状况下,不能用于满足后续申请。

3.3 合并局部内容

如果连贯过早敞开或者申请应用了一个或者多个 Range 标示符响应将可能仅传输了局部表述(representation)。数次像这样的传输之后,缓存将可能收到同一表述的数个 ranges。
如果他们全副共享雷同的强制验证,并且满足 4.3 形容的客户端要求,缓存将可能合并这些 ranges 进同一个响应存储以复用于近期申请的响应。(4.3)
当应用一个或多个存储响应合并为一个新的响应时,缓存应满足
删除存储响应中蕴含 1xx 正告码的 warning 首部字段
保留存储响应中蕴含 2xx 正告码的 warning 首部字段
在新响应中应用除了 Content-Range 以外的首部字段去替换存储响应中的相应字段


4、结构缓存响应

在发动申请时,非以下状况缓存不得复用存储响应:
发送的 URI 申请无效([RFC7230]的第 5.5 节)并与存储的响应匹配。且
存储响应相干的申请办法容许它被用于发动的申请,且
抉择相匹配被响应存储指定的首部字段,(参见第 4.1 节),且
除非存储响应曾经被胜利验证(4.3),否则发动的申请不应该蕴含 no-cache 指令(5.4),也不能蕴含 no-cache 缓存指令(5.2.1),且
除非存储响应曾经被胜利验证(4.3),否则发动的申请不应该蕴含 no-cache 指令(5.2.2.2),且
存储响应,也该当满足:
新鲜度(4.2),亦或者
容许古老的响应(4.2.4),亦或者
胜利的通过验证(4.3)

请留神,下面列出的任何要求都能够被缓存管制扩大笼罩; 见第 5.2.3 节
当存储响应被用于满足一个未经验证的申请,缓存必须生成一个 Age 首部字段(5.1)来代替响应中等效的 current_age(4.2.3)
缓存该当直写(write through)带有对源服务器不平安的办法(译注:非幂等)的申请([rfc7231]的第 4.2.1 节),也就是,在转发申请并收到相应回复之前,缓存不该当容许生成此类申请的回复
请留神,不平安的申请可能使得已存储的响应有效
当超过一个失当的响应被存储,缓存必须应用最近期的响应(被 Date 首部字段所表明)。也能够应用带着 ”Cache-Control: max-age=0″ 或 “Cache-Control: no-cache” 首部字段转发申请去打消响应应用的歧义
如果缓存不在有效期(clock available)内,那么不再每次应用前进行验证的话,不能应用存储响应

4.1 应用 vary 计算辅助键

译注:Vary 是一个 HTTP 响应头部信息,它决定了对于将来的一个申请头,应该用一个缓存的回复 (response) 还是向源服务器申请一个新的回复。它被服务器用来表明在 content negotiation algorithm(内容协商算法)中抉择一个资源代表的时候应该应用哪些头部信息(headers).

当缓存收到了一个能够被带有 Vary 首部字段的存储响应所满足的申请([RFC7231]的第 7.1.4 节),除非全副是抉择的首部字段(unless all of the selecting header),否则不该当应用该响应。被由 Vary 首部字段指定字段用于匹配原始申请(即,与存储响应相关联)与发送申请。
从俩次申请中抉择的首部字段被定义用于匹配,当且仅当首次申请能够被利用以下计划变更为二次申请:
容许首部字段语法增加或移除空白
应用雷同字段名称合并多个反复字段(参见 [RFC7230 的第 3.2 节)
依据标头字段的标准,以已知具备雷同语义的形式对两个标头字段值进行规范化(例如,当程序不重要时对字段值进行从新排序;大小写规范化,其中值定义为不辨别大小写

如果(在任何能够进行解决的序列化之后),申请首部字段仍存在缺失,那么它只能匹配其余申请,即便它仍存在缺失
Vary 值为 ”*”,则始终匹配失败
应用抉择头部字段匹配的存储响应作为被选择响应
如果多个响应可用(潜在的蕴含不携带 Vary 首部字段的响应),缓存将须要抉择其中的一个进行应用,当一个抉择首部字段领有一种已知机制去这样做(例如,Accept 中的 qvalues 值,以及类似的申请首部字段),那么该机制就可歹意被用作抉择更优的响应。剩下的,将会通过 Date 首部字段依据最近日期抉择一个最近期的响应,如第 4 章节所表明。
译注:Accept 申请头中容许品质值语法 https://developer.mozilla.org…
品质值或 q 值和 q 因子用于形容以逗号分隔的列表中值的优先级程序。这是某些 HTTP 标头和 HTML 中容许的非凡语法。值的重要性由后缀标记,’;q=’ 后跟紧随其后的一个值,该值介于 0 和之间 1,最多蕴含三个小数位,最高的值示意最高的优先级。如果不存在,则默认值为 1。

如果没有可用的响应被抉择,那么将不能应用缓存供应于发动的申请。通常,他将会转发(可能含有条件,详见 4.3)申请至原始服务器服务器


4.2 新鲜度

陈腐的响应(fresh response)是指其存在周期(age)仍未超过新鲜度周期(freshness lifetime)。那么古老响应(stale response),就与其正好相同。
响应的新鲜度周期是介于其被源服务器创立到它过期之间的工夫。一个明确的过期工夫则是指源服务器不心愿在未经验证过的状况下被缓存持续应用的工夫。而当没有可用的过期工夫时,则被缓存指定启发式过期工夫
响应存在周期(age)是指其被创立或者胜利通过验证以来存在的工夫
如果一个响应是陈腐(fresh)的,那么他将能够在不与原始服务器获得链接的状况下满足后续申请,从而晋升效率。
次要决定新鲜度的机制是源服务器应用 Expires 首部字段(5.3)或者 max-age 响应指令(5.2.2.8)提供一个未来的明确过期工夫工夫。通常,如果过期前语义的有效性不变更,源服务器将指定一个明确的过期工夫。
如果源服务器心愿每次申请钱呢都强制验证缓存,他能够指定一个过期工夫已表明响应曾经古老。在后续申请中,重用符合条件的缓存之前将会验证古老的缓存响应(4.2.4)
源服务器并不总是提供显示的过期工夫,在某些状况下,缓存也容许启发式的决定过期工夫(4.2.2)
确认响应是否陈腐的算法是:
response_is_fresh = (freshness_lifetime > current_age)
陈腐周期(freshness_lifetime)被定义于 4.2.1 章节,存在周期(current_age)被定义于 4.2.3
客户端能够在申请中发送 max-age 或 min-fresh 的缓存指令,以限度或放松对应响应的新鲜度计算

为了防止日期解析的独特问题,当计算新鲜度时该当:
即便所有的日期格局都被表明为大小写敏感,换内存仍应该应用大小写不敏感的形式匹配天、周、时区
如果缓存接收者的工夫外部接口精确度小于 HTTP-date,那么接收者的外部该当将将过期工夫作为一个等同或者早于接管值的近似工夫来解析
缓存收件者不该当让当地时区影响 age 或过期工夫的计算或比拟
缓存收件者该当将 GMT 或 UTC 以外的时区缩写看作是有效的
请留神,陈腐性仅实用于缓存操作; 它不能用于强制用户代理刷新其显示或从新加载资源。无关缓存和历史机制之间的差别,请参阅第 6 节

4.2 计算新鲜度周期

缓存能够计算保鲜期(示意为 通过应用第一个匹配项来响应 下列的:
如果缓存是共享的,并且应用 s -maxage response 指令(请参阅第 5.2.2.9 节),应用其值或
如果存在 max-age 响应指令(第 5.2.2.8 节),应用其值,或
如果存在 Expires 响应标头字段(第 5.3 节),请应用 它的值减去 Date 响应题目字段的值,或
否则,当响应中没有明确指出过期工夫。将可能可能应用启发式的新鲜度周期;看 4.2.2 节
请留神,因为所有 的信息来自原始服务器。当给定指令存在多个值时(例如,两个 Expires 标头字段,多个 Cache-Control:max-age 指令),则该指令的值被视为有效。缓存将更偏向于认定该新鲜度有效的信息为已过期的

4.2.2 计算启发式新鲜度

因为原始服务器并不总是提供明确的到期工夫,当未指定明确的工夫时,缓存能够应用应用其余标头字段的算法值(例如上次批改工夫)调配启发式到期工夫,以估算正当的到期工夫值。本标准未提供具体阐明运算法令,但的确会对后果施加最坏状况的束缚。
当存储的响应中存在明确的到期工夫时,缓存不得应用启发式办法来确定新鲜度。因为第 3 节中的要求,这意味着,启发式办法只能用于没有显式新鲜度的响应(默认状况下,状态码被定义为可缓存)(请参阅 [RFC7231] 第 6.1 节),而那些没有显式新鲜度的响应将 已被标记为可显式缓存(例如,应用“public”响应指令)
如果响应有一个 last-modified 的题目字段([RFC7232]的第 2.2 节),则激励缓存应用自那个工夫以来不超过距离的一小部分来作为启发式过期值。这个分数的典型设置可能是 10
译注:这里通常是指 Last-Modified 与 Date 差值的 10%
应用启发式缓存策略时,如果超过以后工夫 24 小时且从未正告过,浏览器或者代理服务器应该在响应中产生一个正告首部字段 Warning: 113(5.5.4)。
留神:对于具备查问参数(即那些 蕴含“?”)的 URI,[RFC2616]的 13.9 节禁止缓存计算启发式新鲜度。实际上,这尚未宽泛施行。因而,激励源服务器对于不想缓存的状况发送明确的指令(例如 Cache-Control:no-cache)

4.2.3 计算 age

Age 首部字段被用于形容一个缓存接管到响应音讯的估算时长(Age)。Age 字段的值是指音讯被源服务器创立或者验证之后以来缓存的秒数估算值。
重要的是,age 值是响应沿源服务器的门路驻留在每个缓存中的工夫的总和,并须要加上在网络门路中的传输工夫
重要的是,age 值是响应从源服务器在门路停驻每次缓存的总和值

以下事件被用于计算 age

  • age_value:术语 ”age_value” 以适宜算数运算的模式示意 Age 首部字段,(5.1),如果不可用,则为 0。
  • date_value: 术语“date_value”以适宜于算术运算的模式示意 Date 标头字段的值。无关 Date 首部字段的定义以及对于响应不带 Date 值的标准,请参阅 [RFC7231] 的 7.1.1.2 节
  • now:术语“当初”示意“主机执行计算时钟的以后值”。一个主机应该应用 ntp([rfc5905])或一些相似的协定,使其工夫协调同步 UTC 工夫
  • request_time: 发动申请使得存储响应被触发的工夫
  • response_time: 收到响应时主机时钟的以后值
    译注:
    ntp:网络工夫协定
    Coordinated Universal Time(UTC):世界对立工夫

响应的 age 能够以两种齐全独立的形式计算
apparent_age:如果本地时钟与原始服务器的时钟是协调同步的,response_time 减去 date_value。否则,后果将被零替换为零
corrected_age_value:如果沿响应门路的所有缓存实现 HTTP / 1.1,缓存必须绝对于启动申请的工夫来解释此值,而非收到响应的工夫

apparent_age = max(0, response_time - date_value);  
response_delay = response_time - request_time;  
corrected_age_value = age_value + response_delay

合并为

corrected_initial_age = max(apparent_age, corrected_age_value)

如果缓存对 Age 首部字段的值相信(例如,没有 HTTP / 1.0 hops 存在于 Via 首部字段中),则在这种状况下,corrected_age_value 能够用作 corrected_initial_age
存储响应工夫能够通增加存储响应最初一次被源服务器验证(以秒为单位)与 corrected_initial_age 的和值来计算

resident_time = now - response_time;  
current_age = corrected_initial_age + resident_time

4.2.4 古老响应

“古老的”响应要么具备明确的到期信息,要么容许计算启发式过期,且依据第 4.2 节中的计算,该响应不是新的。
如果协定指令明确禁止缓存生成古老响应 (例如,“no-store”或“no-cache”缓存指令、“MUST-revalidate”缓存 - 响应 - 指令、或实用的“s-maxage”或“proxy-revalidate”缓存 - 响应 - 指令; 请参阅第 5.2.2 节),则缓存必须不生成古老响应。
除非断开连接,否则缓存必须不发送过期响应。(也就是说,它不能分割原始服务器或者找到转发门路),或者明确容许这样做 (例如,max-stale 指令; 参见 5.2.1 节)。
在古老响应中缓存应该生成一个正告头字段,其中蕴含 110 warn-code (参见第 5.5.1 节)。同样,如果缓存断开连接,缓存应该在古老响应中生成 112 warn-code (参见第 5.5.3 节)。
当转发没有 Age 标头字段的响应时,即便响应曾经过期,缓存也不应生成新的 Warning 标头字段。缓存不须要验证在传输过程中变得过期的响应。

4.3 验证

当缓存领有一个或多个申请资源存储响应,但他们之中的任何一个都无奈用于进行响应服务(比如说,因为他们不在陈腐,或者有的无奈被抉择,详见 4.1)。能够应用条件申请机制 1(rfc7232)转发申请给下一个入站服务器一个机会抉择一个无效缓存用以响应。更新流程中的贮存元数据,或者应用新的响应替换存储响应。这个过程被称为响应存储的验证或者重验。

4.3.1 发送验证申请

当发送条件申请进行缓存验证,缓存将中发送一个或多个蕴含来自存储响应验证元数据的条件首部字段,而后由收件人对其进行比拟,以确定存储的响应是否等效于资源的以后表述。
其中一个验证器是在 Last-Modified header 字段 ([RFC7232] 的第 2.2 节)中给出的工夫戳,该工夫戳可用于 If-Modified-Since 头字段用于响应验证,或用于 If-Unmodified-Since 或 If-Range 头字段用于示意抉择 (也就是说,客户机指的是以前取得的带有该工夫戳的示意)。
另一个验证器是在 ETag 头字段 ([RFC7232] 的 2.3 节)中给出的实体标记。一个或多个实体标记,示意一个或多个存储的响应,能够用于 If-None-Match 头部字段用于响应验证,或者用于 If-Match 或 If-Range 头部字段用于示意抉择(即,客户端专门援用一个或多个以前应用列出的实体标记取得的示意)。

4.3.2 解决收到的验证申请

申请链中的每个客户机可能都有本人的缓存,因而中间体上的缓存通常从其余 (出站) 缓存接管条件申请。同样,一些用户代理应用条件申请将数据传输限度到最近批改的示意或实现局部检索示意的传输。

译注:原文中第五章有如 cache-control 等首部字段指令的具体定义。这部分内容 mdn 有更业余的翻译,因而倡议参考 mdn

正文完
 0