HTTP缓存是一种保存资源副本并在下次请求时直接使用该副本的技术,合理的使用缓存能够有效的提高web性能。
浏览器将js文件、css文件、图片等资源缓存,当下次请求这些资源时,能够不发送网络请求直接从缓存中取出,称为缓存命中;或者发送网络请求验证缓存而不是从新接收该资源,称为再验证命中。这两种状况都可以减小冗余数据传输、下降对服务器的要求、提升web性能。在缓存中没有找到副本,直接发送请求给服务器称为缓存未命中。
缓存空间有限,不可能将所有资源所有缓存,所以选择请求频率高的资源进行缓存颇有必要。另外,当服务器上的资源发生能够忽略的改变时,但愿可以继续使用缓存而不是从新请求资源;当资源发生须要客户端知晓的改变时,可以准确的更新缓存内容。这些都须要合理的使用缓存机制。
css
HTTP报文由起始行、首部和实体组成,缓存机制是由首部中的字段控制,下面分别介绍与缓存有关的首部字段。
html
Pragma 与 Expires 字段是HTTP/1.0规定的首部,用来向后兼容只支持 HTTP/1.0 协议的缓存服务器。
Pragma 是通用首部,只有一个值 no-cache ,与 HTTP/1.1 的 Cache-Control: no-cache 效果一致,强制要求缓存在返回缓存的版本以前将请求提交到源头服务器进行验证。
Expires 是响应首部,其值是一个GMT(格林尼治时间),表示资源在该时刻以后过时。这个值是相对服务器上的日期而言的,若是浏览器和服务器上的日期不通,则经过这种方式缓存会产生预期以外的状况。
须要注意的是: Pragma 的优先级很高。当 Pragma 与 Expires 同时存在时,无论资源有没有过时,都会发起验证请求。当 Pragma 与 Cache-Control 同时存在时,也会发起验证请求。
Cache-Control 优先级高于 Expires ,若报文中同时出现了 Expires 和 Cache-Control,则以 Cache-Control 为准。
前端
Last-Modified 是响应首部,其值是一个GMT,表示服务器认定的资源作出修改的时间。包含有 If-Modified-Since 或 If-Unmodified-Since 首部的条件请求会使用该字段。Last-Modified 的时间精确到秒,所以没法识别一秒内进行屡次修改的状况。
If-Modified-Since 是条件式请求首部,其值是上次响应中 Last-Modified 的值。若是服务器在该时间以后修改了资源,则会返回该资源,状态码为200 ;若在该时间以后没有修改资源,则会返回不带主体的响应,状态码是 304 。该请求首部只能用于 GET 或 HEAD 请求中。当与 If-None-Match 同时出现时,只要服务器支持 If-None-Match ,If-Modified-Since 的值就会被忽略。
If-Unmodified-Since 是条件式请求首部,若是所请求的资源在指定的时间以后发生了修改,那么会返回 412 错误;当资源在指定的时间以后没有进行过修改的状况下,服务器会返回请求的资源。
web
ETag 是响应首部,其值是资源的特定版本的标识符,能够在标识符以前添加弱验证器标识 W/ ,HTTP 协议默认使用强验证类型。示例以下:
浏览器
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
ETag: W/"0815"
缓存
强验证类型应用于须要逐个字节相对应的状况,很难有效地生成。弱验证类型应用于用户代理只须要确认资源内容相同便可。即使是有细微差异也能够接受,好比显示的广告不一样,或者是页脚的时间不一样。弱验证器很容易生成,但不利于比较。
If-None-Match 是条件式请求首部,其值是ETag值。若是服务器能匹配对应的ETag,这就意味着资源没有改变,服务器便会发送回一个极短的响应,包含HTTP “304 未修改”的状态。304状态告诉客户端,它的缓存版本是最新的,并应该使用它。
If-Match 是条件式请求首部,只有在服务器的资源与 If-Match中指定的 ETag 匹配的时候, 才容许操做。不匹配的话, 服务器返回412状态码。
服务器
Cache-Control 是通用首部,其值较多,可以灵活的控制缓存。
public:响应能够被客户端以及代理服务器缓存。
private:响应能够被客户端缓存,不能被代理服务器缓存。
no-cache: 不建议使用缓存,使用以前要提交服务器验证。
no-store: 禁止使用缓存。
max-age=<seconds>:设置缓存存储的最大周期,超过这个时间缓存被认为过时(单位秒)。与Expires相反,时间是相对于请求的时间。
s-maxage=<seconds>:共享缓存存储的最大周期,覆盖max-age或者Expires头,可是仅适用于共享缓存(好比各个代理),私有缓存会忽略它。
must-revalidate: 常常跟no-cache混淆,其准确含义是本地副本过时前,可使用本地副本;本地副本一旦过时,必须去源服务器进行有效性校验。
max-stale=<seconds>:代表客户端愿意接收一个已通过期的资源。能够设置一个可选的秒数,表示响应不能已通过时超过该给定的时间。
网络
浏览器缓存分为强缓存、协商缓存,其中强缓存直接使用本地缓存,不发请求到服务器。协商缓存会将缓存资源的信息发送到服务器,由服务器来断定是否使用本地缓存。
性能
缓存策略肯定的第一步是根据上次访问资源时响应首部判断是否使用缓存。若是响应首部中有下列字段则不使用缓存,从新发起网络请求来下载资源。
学习
Cache-Control: no-store
复制代码
若是判断可使用缓存,第二步是肯定是否使用协商缓存,而不是直接使用强缓存。若是响应首部中有如下三种的任一种则将资源信息放入首部发起网络请求,若服务器断定缓存资源可用则返回 304 状态码,告诉客户端直接使用缓存资源。若断定资源不可用则返回 200 状态码,并从新发送资源。
Cache-Control:max-age=0
Cache-Control: no-cache
Pragma: no-cache
复制代码
若是可使用缓存,且没必要直接使用协商缓存,则执行第三步:校验缓存资源新鲜度。若是资源未过时则使用强缓存。资源过时不表明必定不采用,通过服务器确认后资源若未改变则使用该资源,会根据响应头部来更新资源的新鲜度。
服务器经过如下两个首部字段来为资源设置“过时日期”,在过时日期以前能够任意使用该资源而不用发送网络请求。
Cache-Control:max-age=<seconds>
Expires: <http-date>
复制代码
max-age 的值是一个相对于请求的时间,客户端发起请求时会根据上次请求的时间加上max-age 来判断资源是否过时。
Expires的优先级低于 max-age,若是在Cache-Control响应头设置了 "max-age" 或者 "s-max-age" 指令,那么 Expires 头会被忽略。
有一点须要注意:Last-Modified 首部字段可以计算出一个缓存时间。若是容许使用强缓存,且 max-age 和 expires 属性都没有,若存在 Last-Modified 属性,则能够计算出一个相似 max-age 的相对“过时日期”。计算公式为响应首部中 Date 的值减去 Last-Modified 的值乘以 10% 。
协商缓存的主要根据是响应首部中的两个属性:Last-Modified、ETag。Last-Modified 是从时间维度来断定资源是否改变,ETag是从资源id是否改变来判断资源是否改变的。
Last-Modified 代表服务器认定的资源作出修改的日期及时间。进行协商缓存时,客户端请求首部中会加入 If-Modified-Since 属性,其值为响应首部的 Last-Modified 属性。服务器判断该时间以后是否修改了资源,若是资源被修改,则会返回该资源,状态码为200 ;若没有修改资源,则返回不带主体的响应,状态码是 304 。
响应首部中有ETag属性时,在进行协商缓存时请求首部中会添加 If-None-Match 属性。ETag 的优先级要高于 Last-Modified,也就是说服务器优先根据 ETag 来判断资源是否被修改。若是ETag不匹配,则直接返回新的资源,状态码为 200;若是ETag匹配,则说明资源未被修改,返回 304 状态码,通知客户端继续使用缓存资源。
客户端根据响应首部肯定缓存策略的步骤为:首先肯定是否使用缓存,若使用缓存则进一步确认是否直接使用协商缓存。若是没有强制要求使用协商缓存,优先查看缓存资源是否过时,未过时时使用缓存资源,过时则进行协商缓存。
协商缓存主要根据 Last-Modified 或 ETag 首部字段来肯定是否使用缓存资源。ETag 的优先级要高于 Last-Modified,在没有 ETag 的状况下才会使用 Last-Modified 来断定。若是服务器断定资源可用回返回 304 状态码,通知客户端直接使用缓存资源,不然返回 200 状态码以及新的资源。
欢迎关注公众号:前端桃花源,互相交流学习!
一、完全弄懂 Http 缓存机制 - 基于缓存策略三要素分解法
二、MDN-HTTP缓存
三、HTTP缓存控制小结
四、前端学HTTP之缓存