10分钟彻底搞懂Http的强制缓存和协商缓存(小结)


Posted in Javascript onAugust 30, 2018

浏览器缓存

浏览器缓存是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档。

所以根据上面的特点,浏览器缓存有下面的优点:

  • 减少冗余的数据传输
  • 减少服务器负担
  • 加快客户端加载网页的速度

浏览器缓存是Web性能优化的重要方式。那么浏览器缓存的过程究竟是怎么样的呢?

在浏览器第一次发起请求时,本地无缓存,向web服务器发送请求,服务器起端响应请求,浏览器端缓存。过程如下:

在第一次请求时,服务器会将页面最后修改时间通过Last-Modified标识由服务器发送给客户端,客户端记录修改时间;服务器还会生成一个Etag,并发送给客户端。

浏览器后续再次进行请求时:

浏览器缓存主要分为强强缓存(也称本地缓存)和协商缓存(也称弱缓存)。根据上图,浏览器在第一次请求发生后,再次发送请求时:

  • 浏览器请求某一资源时,会先获取该资源缓存的header信息,然后根据header中的Cache-Control和Expires来判断是否过期。若没过期则直接从缓存中获取资源信息,包括缓存的header的信息,所以此次请求不会与服务器进行通信。这里判断是否过期,则是强缓存相关。后面会讲Cache-Control和Expires相关。
  • 如果显示已过期,浏览器会向服务器端发送请求,这个请求会携带第一次请求返回的有关缓存的header字段信息,比如客户端会通过If-None-Match头将先前服务器端发送过来的Etag发送给服务器,服务会对比这个客户端发过来的Etag是否与服务器的相同,若相同,就将If-None-Match的值设为false,返回状态304,客户端继续使用本地缓存,不解析服务器端发回来的数据,若不相同就将If-None-Match的值设为true,返回状态为200,客户端重新机械服务器端返回的数据;客户端还会通过If-Modified-Since头将先前服务器端发过来的最后修改时间戳发送给服务器,服务器端通过这个时间戳判断客户端的页面是否是最新的,如果不是最新的,则返回最新的内容,如果是最新的,则返回304,客户端继续使用本地缓存。

一 强制缓存

强制缓存整体流程比较简单,就是在第一次访问服务器取到数据之后,在过期时间之内不会再去重复请求。实现这个流程的核心就是如何知道当前时间是否超过了过期时间。

强制缓存的过期时间通过第一次访问服务器时返回的响应头获取。在 http 1.0 和 http 1.1 版本中通过不同的响应头字段实现。

http 1.0

在 http 1.0 版本中,强制缓存通过 Expires 响应头来实现。 expires 表示未来资源会过期的时间。也就是说,当发起请求的时间超过了 expires 设定的时间,即表示资源缓存时间到期,会发送请求到服务器重新获取资源。而如果发起请求的时间在 expires 限定的时间之内,浏览器会直接读取本地缓存数据库中的信息(from memory or from disk),两种方式根据浏览器的策略随机获取。

http 1.1

在 http 1.1 版本中,强制缓存通过 Cache-Control 响应头来实现。Cache-Control 拥有多个值:

  • private:客户端可以缓存
  • public:客户端和代理服务器均可缓存;
  • max-age=xxx:缓存的资源将在 xxx 秒后过期;
  • no-cache:需要使用协商缓存来验证是否过期;
  • no-store:不可缓存

最常用的字段就是 max-age=xxx ,表示缓存的资源将在 xxx 秒后过期。一般来说,为了兼容,两个版本的强制缓存都会被实现。

总结

强制缓存只有首次请求才会跟服务器通信,读取缓存资源时不会发出任何请求,资源的 Status 状态码为 200,资源的 Size 为 from memory 或者 from disk ,http 1.1 版本的实现优先级会高于 http 1.0 版本的实现。

二 协商缓存

协商缓存与强制缓存的不同之处在于,协商缓存每次读取数据时都需要跟服务器通信,并且会增加缓存标识。在第一次请求服务器时,服务器会返回资源,并且返回一个资源的缓存标识,一起存到浏览器的缓存数据库。当第二次请求资源时,浏览器会首先将缓存标识发送给服务器,服务器拿到标识后判断标识是否匹配,如果不匹配,表示资源有更新,服务器会将新数据和新的缓存标识一起返回到浏览器;如果缓存标识匹配,表示资源没有更新,并且返回 304 状态码,浏览器就读取本地缓存服务器中的数据。

在 http 协议的 1.0 和 1.1 版本中也有不同的实现方式。

http 1.0

在 http 1.0 版本中,第一次请求资源时服务器通过 Last-Modified 来设置响应头的缓存标识,并且把资源最后修改的时间作为值填入,然后将资源返回给浏览器。在第二次请求时,浏览器会首先带上 If-Modified-Since 请求头去访问服务器,服务器会将 If-Modified-Since 中携带的时间与资源修改的时间匹配,如果时间不一致,服务器会返回新的资源,并且将 Last-Modified 值更新,作为响应头返回给浏览器。如果时间一致,表示资源没有更新,服务器返回 304 状态码,浏览器拿到响应状态码后从本地缓存数据库中读取缓存资源。

这种方式有一个弊端,就是当服务器中的资源增加了一个字符,后来又把这个字符删掉,本身资源文件并没有发生变化,但修改时间发生了变化。当下次请求过来时,服务器也会把这个本来没有变化的资源重新返回给浏览器。

http 1.1

在 http 1.1 版本中,服务器通过 Etag 来设置响应头缓存标识。Etag 的值由服务端生成。在第一次请求时,服务器会将资源和 Etag 一并返回给浏览器,浏览器将两者缓存到本地缓存数据库。在第二次请求时,浏览器会将 Etag 信息放到 If-None-Match 请求头去访问服务器,服务器收到请求后,会将服务器中的文件标识与浏览器发来的标识进行对比,如果不相同,服务器返回更新的资源和新的 Etag ,如果相同,服务器返回 304 状态码,浏览器读取缓存。

总结

协商缓存每次请求都会与服务器交互,第一次是拿数据和标识的过程,第二次开始,就是浏览器询问服务器资源是否有更新的过程。每次请求都会传输数据,如果命中缓存,则资源的 Status 状态码为 304 而不是 200 。同样的,一般来讲为了兼容,两个版本的协商缓存都会被实现,http 1.1 版本的实现优先级会高于 http 1.0 版本的实现。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery实现图片裁剪思路及实现
Aug 16 Javascript
jQuery插件boxScroll实现图片轮播特效
Jul 14 Javascript
详解JavaScript时间格式化
Dec 23 Javascript
正则表达式(语法篇推荐)
Jun 24 Javascript
connection reset by peer问题总结及解决方案
Oct 21 Javascript
VUE-cli3使用 svg-sprite-loader
Oct 20 Javascript
详解Vue2 添加对scss的支持
Jan 02 Javascript
JS栈stack类的实现与使用方法示例
Jan 31 Javascript
jquery无缝图片轮播组件封装
Nov 25 jQuery
Vue 2.0 中依赖注入 provide/inject组合实战
Jun 20 Javascript
Node使用Nodemailer发送邮件的方法实现
Feb 24 Javascript
vue项目中使用rem,在入口文件添加内容操作
Nov 11 Javascript
解决jQuery使用append添加的元素事件无效的问题
Aug 30 #jQuery
jsonp跨域及实现百度首页联想功能的方法
Aug 30 #Javascript
解决使用bootstrap的dropdown部件时报错:error:Bootstrap dropdown require Popper.js问题
Aug 30 #Javascript
解决vue的变量在settimeout内部效果失效的问题
Aug 30 #Javascript
JS+HTML5 Canvas实现简单的写字板功能示例
Aug 30 #Javascript
详解React native fetch遇到的坑
Aug 30 #Javascript
对Vue2 自定义全局指令Vue.directive和指令的生命周期介绍
Aug 30 #Javascript
You might like
php获取url字符串截取路径的文件名和扩展名的函数
2010/01/22 PHP
PHP计划任务之关闭浏览器后仍然继续执行的函数
2010/07/22 PHP
php CI框架插入一条或多条sql记录示例
2014/07/29 PHP
PHP基于数组实现的分页函数实例
2014/08/20 PHP
php判断类是否存在函数class_exists用法分析
2014/11/14 PHP
PHP数组函数知识汇总
2016/05/12 PHP
php将文件夹打包成zip文件的简单实现方法
2016/10/04 PHP
thinkPHP实现签到功能的方法
2017/03/15 PHP
jQuery select控制插件
2009/08/17 Javascript
清空上传控件input file的值
2010/07/03 Javascript
Jquery倒数计时按钮setTimeout的实例代码
2013/07/04 Javascript
JS过滤url参数特殊字符的实现方法
2013/12/24 Javascript
drag-and-drop实现图片浏览器预览
2015/08/06 Javascript
jQuery实现美观的多级动画效果菜单代码
2015/09/06 Javascript
js调出上下文菜单的实例
2015/12/17 Javascript
js与jQuery实现checkbox复选框全选/全不选的方法
2016/01/05 Javascript
jQuery设置单选按钮radio选中/不可用的实例代码
2016/06/24 Javascript
javascript封装addLoadEvent实现页面同时加载执行多个函数的方法
2016/07/25 Javascript
关于原生js中bind函数的简单实现
2016/08/10 Javascript
函数式编程入门实践(一)
2019/04/20 Javascript
微信小程序实现比较功能的方法汇总(五种方法)
2020/03/07 Javascript
javascript实现前端input密码输入强度验证
2020/06/24 Javascript
Python脚本实现DNSPod DNS动态解析域名
2015/02/14 Python
详解Python装饰器
2019/03/25 Python
python 猴子补丁(monkey patch)
2019/06/26 Python
python 实现return返回多个值
2019/11/19 Python
使用python 的matplotlib 画轨道实例
2020/01/19 Python
ToysRus日本官网:玩具反斗城
2018/09/08 全球购物
Anya Hindmarch官网:奢侈设计师手袋及配饰
2018/11/15 全球购物
美国台面电器和厨具品牌:KitchenAid
2019/04/12 全球购物
计算机相关的自我评价
2014/01/15 职场文书
2015年纪检监察工作总结
2015/04/08 职场文书
2015年财政所工作总结
2015/04/25 职场文书
庆祝教师节主持词
2015/07/06 职场文书
PHP使用非对称加密算法RSA
2021/04/21 PHP
用Python生成会跳舞的美女
2022/01/18 Python