资讯专栏INFORMATION COLUMN

谈谈HTTP缓存

xiaodao / 697人阅读

摘要:但遗憾的是,该响应已经过期。大多数情况下,不是必需的,因为明确的缓存信息例如已表示响应是可以缓存的。表示响应只为单个用户缓存,因此不允许中间缓存对其进行缓存。这样,即使文件缓存了,也可以得到更新。

在上一篇文章中,我们讲到造成网络性能下降的主要原因是延迟,而非带宽。那么为了更好地让我们的网站能快速响应用户的请求,我们就必须对一些常用资源进行缓存,
以免每次用户访问都请求一遍,这也是网站性能优化比较重要的一个环节。

现代浏览器都自带了HTTP缓存实现功能,我们所要做的只是确保我们正确地设置了HTTP响应头,以便指示浏览器何时缓存响应以及缓存多久。

首先说明一点,缓存并不是说浏览器不会对该资源再次发起请求,每种缓存机制都有自己的过期策略,我们常常看到的304状态码就表面该资源已被缓存了,但浏览器不知道有没有过期,
再次使用该资源的时候,会向服务器发起请求验证一遍,如果缓存资源有效,则会返回304状态码。最坏的情况下,则是该资源过期了,还得重新发起一次请求去获取。另一种则是浏览
器连问都不问服务器,直接就从本地硬盘读取,此时可以看到浏览器给出的响应是200(from disk cache)。

ETag

假设我们有一份css资源,我们在获取该资源一段时间后又刷新了页面,这时浏览器就会检查本地资源并查找之前的响应。但遗憾的是,该响应已经过期。此时,浏览器可以直接发起请求
重新去获取一份新的数据,但这样做效率实在是太低了。若资源本身改变了还好说,但若资源本身并没有改变呢,重新获取一份数据成本太高。

这时ETag就是用来解决这个问题的,ETag可以看做是这个文件的hash值,只要文件内容没有改变,ETag值则不会变。客户端完全不需要了解ETag是怎么生成的,只需要在下一次请求的
时候将ETag带上即可(浏览器发起请求时,if-None-Match中的值就是该ETag值),若该ETag与服务器匹配,则会返回304,告诉浏览器可以使用该缓存,从而跳过再次下载过程。

Cache-Control

Cache-Control指令控制谁在什么条件下可以缓存响应以及可以缓存多久,如上面所说,有些资源我们可以直接从本地磁盘获取(from disk cache),而无需再次发起请求询问服务器,这
便是Cache-Control的作用。Cache-Control是HTTP/1.1规范中定义的,现在基本用它来取代Expires。

"no-cahce"与"no-store"

"no-cache"表示必须与服务器确认返回的响应是否发生了变化,然后才能使用该响应来满足后续对同一资源的请求。该值可以配合ETag来使用,浏览器通过请求If-None-Match来向服务器
验证该资源是否过期,若资源未发生变化,则避免下载。

"no-store"则表示无论什么情况下,浏览器都不得缓存该资源,即便存在ETag也一样,每次都得从服务器中获取。

"public"与"private"

如果响应被标记为"public",则即使它有关联的 HTTP 身份验证,甚至响应状态代码通常无法缓存,也可以缓存响应。大多数情况下,“public”不是必需的,因为明确的缓存信息(例如“max-age”)
已表示响应是可以缓存的。

"private"表示响应只为单个用户缓存,因此不允许中间缓存对其进行缓存。例如,用户浏览器可以缓存包含用户私人信息的HTML网页,但CDN则不可以。

"max-age"

该值是Cache-Control中用得比较多的一个值,表示从请求的时间开始,允许获取的响应被缓存的最长时间(单位:秒)。例如,max-age设置为100,则表示该资源可以缓存100秒,100秒后,再次
请求该资源,浏览器则会携带ETag去询问服务器该资源是否过期。在该资源未过期时,访问该资源,浏览器则从本地磁盘获取,不会发起任何网络请求。

定义最佳Cache-Control策略

如上图所示,如果资源不需要缓存,我们设置Cache-Control的值为no-store;如果资源需要缓存且每次都得向服务器验证,则为no-cache;如果中间设备可以缓存,设置为public,中间设备不
可缓存,设置为private;如果缓存有时间限制,我们设置max-age的值。private与public的值可以与max-age同时使用,中间用分号隔开。

Expires

Expires头指定了一个日期/时间,在这个日期/时间之后,HTTP响应被认为是过时的,一个无效的日期,例如0也表示该资源过时。如果还设置了max-age,则该请求头会被忽略。

总结

使用缓存最好的方式就是ETag配合Cache-Control,并设置相应的max-age,一般情况下,不再建议使用Expires头。如果资源许久都不更新,max-age可以设置比较长的时间,但是这样会有个问题就是
在缓存期间,该文件发生改变,但相应的客户端却还是在使用旧版本,解决的方法就是每个文件都带一个相应内容的hash值作为文件名。这样,即使文件缓存了,也可以得到更新。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/61913.html

相关文章

  • 谈谈 redis 在项目中的常见使用场景

    摘要:参考源码邮件发送,限流,漏桶与令牌桶分布式可以通过的来在间进行交流。可以参考以下项目 最近在写一个脚手架,发现其中 redis 的使用场景还挺多,于是总结下它的常见使用场景 本文链接: https://shanyue.tech/post/red... github 备份: https://github.com/shfshanyue... 缓存 > set User:1:nam...

    Towers 评论0 收藏0
  • 金三银四,2019大厂Android高级工程师面试题整理

    摘要:原文地址游客前言金三银四,很多同学心里大概都准备着年后找工作或者跳槽。最近有很多同学都在交流群里求大厂面试题。 最近整理了一波面试题,包括安卓JAVA方面的,目前大厂还是以安卓源码,算法,以及数据结构为主,有一些中小型公司也会问到混合开发的知识,至于我为什么倾向于混合开发,我的一句话就是走上编程之路,将来你要学不仅仅是这些,丰富自己方能与世接轨,做好全栈的装备。 原文地址:游客kutd...

    沈建明 评论0 收藏0
  • 金三银四,2019大厂Android高级工程师面试题整理

    摘要:原文地址游客前言金三银四,很多同学心里大概都准备着年后找工作或者跳槽。最近有很多同学都在交流群里求大厂面试题。 最近整理了一波面试题,包括安卓JAVA方面的,目前大厂还是以安卓源码,算法,以及数据结构为主,有一些中小型公司也会问到混合开发的知识,至于我为什么倾向于混合开发,我的一句话就是走上编程之路,将来你要学不仅仅是这些,丰富自己方能与世接轨,做好全栈的装备。 原文地址:游客kutd...

    tracymac7 评论0 收藏0
  • 谈谈对模块化的理解

    摘要:重要的模块化规范有几个,模块机制,,。模块化的目的在于营造安全封闭的作用域且具有易于引用接口,按我的理解可分为模块定义模块引入两部分。它的定义如下模块标识符模块对外输出的值调用该模块的模块。在中,有一部分模块由提供,称之为核心模块。 重要的模块化规范有几个:commonjs,ES6模块机制,AMD,CMD。由于业务中一直接触的都是Vue+webpack+babel架构的项目,在封装代码...

    silvertheo 评论0 收藏0
  • 谈谈Redis的SETNX

    摘要:下面以目前社区里最流行的扩展为例,实现一段演示代码缓存过期时,通过获取锁,如果成功了,那么更新缓存,然后删除锁。 在 Redis 里,所谓 SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果,不过很多人没有意识到 SETNX 有陷阱! 比如说:某个查询数据库的接口,因为调用量比较大,所以加了缓存,并设定缓存过期后刷新,问题...

    ztyzz 评论0 收藏0

发表评论

0条评论

xiaodao

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<