HTTP缓存是一种保存资源副本并在下次请求时直接使用该副本的技术,合理的使用缓存可以有效的提升web性能。

  浏览器将js文件、css文件、图片等资源缓存,当下次请求这些资源时,可以不发送网络请求直接从缓存中取出,称为缓存命中;或者发送网络请求验证缓存而不是重新接收该资源,称为再验证命中。这两种情况都能够减少冗余数据传输、降低对服务器的要求、提高web性能。在缓存中没有找到副本,直接发送请求给服务器称为缓存未命中

  缓存空间有限,不可能将全部资源全部缓存,因此选择请求频率高的资源进行缓存很有必要。另外,当服务器上的资源发生可以忽略的改变时,希望能够继续使用缓存而不是重新请求资源;当资源发生需要客户端知晓的改变时,能够准确的更新缓存内容。这些都需要合理的使用缓存机制。

一、与缓存有关的首部字段

  HTTP报文由起始行首部实体组成,缓存机制是由首部中的字段控制,下面分别介绍与缓存有关的首部字段。

1、Pragma与Expires

  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 为准。

2、Last-Modified、If-Modified-Since与If-Unmodified-Since

  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 错误;当资源在指定的时间之后没有进行过修改的情况下,服务器会返回请求的资源。

3、ETag、If-None-Match与If-Match

  ETag 是响应首部,其值是资源的特定版本的标识符,可以在标识符之前添加弱验证器标识 W/ ,HTTP 协议默认使用强验证类型。示例如下:

ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

ETag: W/"0815"

  强验证类型应用于需要逐个字节相对应的情况,很难有效地生成。弱验证类型应用于用户代理只需要确认资源内容相同即可。即便是有细微差别也可以接受,比如显示的广告不同,或者是页脚的时间不同。弱验证器很容易生成,但不利于比较。

  If-None-Match 是条件式请求首部,其值是ETag值。如果服务器能匹配对应的ETag,这就意味着资源没有改变,服务器便会发送回一个极短的响应,包含HTTP “304 未修改”的状态。304状态告诉客户端,它的缓存版本是最新的,并应该使用它。

  If-Match 是条件式请求首部,只有在服务器的资源与 If-Match中指定的 ETag 匹配的时候, 才允许操作。不匹配的话, 服务器返回412状态码。

4、Cache-Control

  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>:表明客户端愿意接收一个已经过期的资源。可以设置一个可选的秒数,表示响应不能已经过时超过该给定的时间。

二、缓存策略分析

  浏览器缓存分为强缓存协商缓存,其中强缓存直接使用本地缓存,不发请求到服务器。协商缓存会将缓存资源的信息发送到服务器,由服务器来判定是否使用本地缓存。



  客户端是否使用本地缓存的规则如图所示,下面分别介绍:

1、缓存策略确定

  缓存策略确定的第一步是根据上次访问资源时响应首部判断是否使用缓存。如果响应首部中有下列字段则不使用缓存,重新发起网络请求来下载资源。

Cache-Control: no-store

  如果判断可以使用缓存,第二步是确定是否使用协商缓存,而不是直接使用强缓存。如果响应首部中有以下三种的任一种则将资源信息放入首部发起网络请求,若服务器判定缓存资源可用则返回 304 状态码,告诉客户端直接使用缓存资源。若判定资源不可用则返回 200 状态码,并重新发送资源。

Cache-Control:max-age=0
Cache-Control: no-cache
Pragma: no-cache

  如果可以使用缓存,且不必直接使用协商缓存,则执行第三步:校验缓存资源新鲜度。如果资源未过期则使用强缓存。资源过期不代表一定不采用,经过服务器确认后资源若未改变则使用该资源,会根据响应头部来更新资源的新鲜度。

2、强缓存

  服务器通过以下两个首部字段来为资源设置“过期日期”,在过期日期之前可以任意使用该资源而不用发送网络请求。

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% 。

3、协商缓存

  协商缓存的主要根据是响应首部中的两个属性: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 状态码以及新的资源。



欢迎关注公众号:前端桃花源,互相交流学习!

参考资料


1、彻底弄懂 Http 缓存机制 - 基于缓存策略三要素分解法

2、MDN-HTTP缓存

3、HTTP缓存控制小结

4、前端学HTTP之缓存

网络学习笔记(三):HTTP缓存的更多相关文章

  1. muduo网络库学习笔记(三)TimerQueue定时器队列

    目录 muduo网络库学习笔记(三)TimerQueue定时器队列 Linux中的时间函数 timerfd简单使用介绍 timerfd示例 muduo中对timerfd的封装 TimerQueue的结 ...

  2. 物联网学习笔记三:物联网网关协议比较:MQTT 和 Modbus

    物联网学习笔记三:物联网网关协议比较:MQTT 和 Modbus 物联网 (IoT) 不只是新技术,还是与旧技术的集成,其关键在于通信.可用的通信方法各不相同,但是,各种不同的协议在将海量“事物”连接 ...

  3. SpringBoot学习笔记:Redis缓存

    SpringBoot学习笔记:Redis缓存 关于Redis Redis是一个使用ANSI C语言编写的免费开源.支持网络.可基于内存亦可以持久化的日志型.键值数据库.其支持多种存储类型,包括Stri ...

  4. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  5. [Firefly引擎][学习笔记三][已完结]所需模块封装

    原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读:        笔记三主要就是各个模块的封装了,这里贴 ...

  6. JSP学习笔记(三):简单的Tomcat Web服务器

    注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...

  7. java之jvm学习笔记三(Class文件检验器)

    java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...

  8. VSTO学习笔记(三) 开发Office 2010 64位COM加载项

    原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...

  9. Java IO学习笔记三

    Java IO学习笔记三 在整个IO包中,实际上就是分为字节流和字符流,但是除了这两个流之外,还存在了一组字节流-字符流的转换类. OutputStreamWriter:是Writer的子类,将输出的 ...

  10. NumPy学习笔记 三 股票价格

    NumPy学习笔记 三 股票价格 <NumPy学习笔记>系列将记录学习NumPy过程中的动手笔记,前期的参考书是<Python数据分析基础教程 NumPy学习指南>第二版.&l ...

随机推荐

  1. Redis (一)Redis简介、安装部署

    Redis是一个开源的,先进的 key-value 存储可用于构建高性能,可扩展的 Web 应用程序的解决方案. 既然是key-value,对于Java开发来说更熟悉的是Map集合.那就有问题了,有M ...

  2. NYOJ781 又见回文数

    又见回文数 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描写叙述 冷淡的回文数被水了,各种被水,然后他非常生气,然后... 一个数从左边读和从右边读一样,就说这个数是回文数 ...

  3. Poco logger 日志使用小析

    Poco logger 日志使用小析 Poco logger 日志使用小析 日志 logger 库选择 Pocologger 架构简析 步骤一 生成消息 步骤二 写入logger 步骤三 导入chan ...

  4. VC除零异常(错误)捕获

    // testFinally.cpp : Defines the entry point for the console application. // #include "stdafx.h ...

  5. WPF党旗和国徽!

    原文:WPF党旗和国徽! 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/yangyisen0713/article/details/18087007 ...

  6. PO、VO、BO、DTO、POJO、DAO之间的关系

    J2EE开发中大量的专业缩略语很是让人迷惑,尤其是跟一些高手讨论问题的时候,三分钟就被人家满口的专业术语喷晕了,PO VO BO DTO POJO DAO,一大堆的就来了(听过老罗对这种现象的批判的朋 ...

  7. Android新的漏洞的应用程序中的发现!

    最近,趋势科技发现一些Android中的漏洞应用程序内存.来发动攻击.我们调查了两个受影响的应用程序,大家来感受一下: .超过一千万次安装.及在下载页面拥有数十万笔用户留言的生产力应用程序(生产力应用 ...

  8. EF context.SaveChanges()特点

    EF context.SaveChanges()特点 1 一次连接保存多条数据(工作单元模式): 2 内部通过事务来执行,如果一条数据保存失败,执行回滚操作: 3 延时加载 var userList= ...

  9. Bootstrap 图片形状

    @{    Layout = null;}<!DOCTYPE html><html><head>    <meta name="viewport&q ...

  10. glibc内存管理方式

    程序员接触的内存空间和系统接触的物理内存空间是有所区别的.对于一般进程来讲,他面对的是一个线性虚拟内存空间:地址从0到最大值.每一个进程面对的虚拟内存空间都是一样的,都享有全部的内存地址.虚拟内存空间 ...