HTTP缓存详解
发布于 3 年前 作者 albert 5595 次浏览 来自 分享

原文地址:<a href=“http://muchstudy.com/2016/08/18/HTTP缓存详解/” target="_blank">HTTP缓存详解</a>

本文对我目前所了解的HTTP缓存知识做一个分享,希望能通过本文能让大家对HTTP缓存的基础知识有所了解。

使用缓存有如下几个好处:

  • 缓存减少了冗余的数据传输, 节省了你的网络费用。
  • 缓存缓解了网络瓶颈的问题。 不需要更多的带宽就能够更快地加载页面。
  • 缓存降低了对原始服务器的要求。 服务器可以更快地响应,避免过载的出现。
  • 缓存降低了距离时延, 因为从较远的地方加载页面会更慢一些。

一、HTTP请求的过程

浏览器-源服务器请求过程

我们可以知道,从在浏览器地址栏敲入域名-DNS解析-实际IP-(中间可能多个代理服务器分发)- 源服务器,请求抵达源服务器后,在服务器上找到请求的资源,再通过代理服务器一层层的返回数据到浏览器端。

缓存要解决的核心问题为减少客户端对源服务器的HTTP请求,提升性能。试想,像jquery、bootstrap这种更新不频繁的资源当然没有必要每次都从源服务器上获取。

实际上大部分静态文件在下一次内容更新之前都没有必要再走一遍网络从源服务器获取

二、服务器控制缓存的能力

当客户端第一次请求服务器端的资源时,服务器端可以通过如下几种方式控制资源的缓存能力。

  1. Cache-Control:no-store,禁止缓存对响应进行复制。
  2. Cache-Control:no-cache,以前老认为这个是不缓存的意思,下面从《HTTP权威指南》摘录一段解释:标识为 no-cache 的响应实际上是可以存储在本地缓存区中的。 只是在与原始服务器进行新鲜度再验证之前,缓存不能将其提供给客户端使用。这个首部使用 donot-serve-from-cache-without-revalidation 这个名字会更恰当一些。
  3. Cache-Control: must-revalidate,在事先没有跟原始服务器进行再验证的情况下,不能提供这个对象的陈旧副本。 缓存仍然可以随意提供新鲜的副本。如果在缓存进行 must-revalidate 新鲜度检查时,原始服务器不可用,缓存就必须返回一条 504 Gateway Timeout 错误。
  4. Cache-Control: max-age=3600,从服务器将文档传来之时起, 可以认为此文档处于新鲜状态的秒数。
  5. Expires: Fri, 05 Jul 2002, 05:00:00 GMT,实际的过期日期,不推荐使用。
  6. 不附加过期信息,让缓存确定自己的过期日期,如果响应中没有 Cache-Control: max-age 首部, 也没有 Expires 首部, 缓存可以计算出一个试探性最大使用期。 可以使用任意算法, 但如果得到的最大使用期大于 24 小时, 就应该向响应首部添加一个 Heuristic Expiration Warning( 试探性过期警告, 警告 13) 首部。LM-Factor 算法是一种很常用的试探性过期算法。

三、强缓存

浏览器强缓存什么意思呢,就是说当请求一个资源时,直接从本地的浏览器缓存中读取,不发起HTTP请求,对于源服务器来讲,好爽!~~

下面是京东首页的截图

浏览器强缓存

像这种显示from cache的就是直接读取的浏览器本地缓存,那么HTTP是如何控制直接读取本地缓存的呢?有如下两种方式。

名称 说明
Expires 响应失效的日期和时间。类似于:Expires:Sat, 20 Aug 2016 01:40:57 GMT,绝对值,告诉客户端在这个时间点之后资源过期,需要重新从服务器取。
Cache-Control 类似于:Cache-Control:max-age=315360000,相对值,在多久后过期

通过上面两种方式,当资源的缓存还在有效期时,浏览器直接从本地缓存中取资源,而不是发起HTTP请求从源服务器取。由于客户端与服务器端存在时间差,Expires并不是那么的靠谱,所以建议使用max-age

四、协商缓存

当浏览器强缓存过期后,就会触发协商缓存机制。这个时候需向服务器发送一个http请求,带上如下列表中的头部信息,如果符合规则(即服务器跟客户端资源一致),直接返回304,不再返回资源内容;否则,返回状态码200与资源内容;最后,更新缓存头信息。

名称 说明
If-Modified-Since 告诉服务器只要服务器在这个时间之后又对资源做了修改则发送该资源
If-None-Match与ETag 根据资源内容是否变更来判断是否继续使用本地缓存。第一次请求资源时,服务器在response头信息中设置ETag,当资源过期后再次向服务器请求时用If-None-Match:ETag去验证资源是否变更

从《HTTP权威指南》中截个图来说明If-None-Match与ETag如何使用的

If-None-Match与ETag

当本地缓存过期后,客户端如何知到该使用上述哪种方式呢?其实,在客户端第一次请求资源时,服务器需要带上Last-ModifiedETag,然后缓存起来,当缓存失效重新进行新鲜度检查时,这两个头部就可以派上用场了。一般来说,ETag的优先级高于Last-Modified

五、总结

上面分享了缓存的基础知识,在实际情景中,最理想的情况我们当然希望所有静态资源都使用强缓存,当第一次使用资源后,下一次就不再从源服务器取,而是直接从本地获取,这样一来就大大减轻了服务器的压力。But!如果这样的话,那当下一版本发布,用户如何拿到我的更新呢?

这里已经有一个讲得<a href=“https://www.zhihu.com/question/20790576” >通熟易懂的轮子</a>了,我就不再重新造了。

11 回复

赞,楼主总结了系列http知识,要是能把稳中附图的连接修改了更好了

@jiangliqin 传了一份 已解决图片显示不出来的问题

请问楼主,如果没有设置Expires、Cache-Control,浏览器还会直接读取本地缓存么? 自己试验了,竟然是会的,很不理解?

@hxyfj 看第二个章节的第六点不附加过期信息,让缓存确定自己的过期日期。现在的浏览器都比较智能了,会自己计算一个试探性最大使用期

@hxyfj 这在我之前一篇的<a href=“http://muchstudy.com/2016/08/20/HTTP连接管理/”>HTTP连接管理</a>里面的keep-alive一样,新版本的很多浏览器都会自动去设置Connection: Keep-Alive

没充分的理解 已收藏

其实这些都是书本上的知识,在大型项目里一般是设置最大的maxage, css或者js文件打包成几个或者一个文件并且以其hash(MD5)来作为文件名. 比如main-i3409fjiojrwoi.js

这样在下次版本迭代后只要文件有变化文件的hash就一定会变.

或者使用离线web,这就要用到manifest了。

condition cache 可以这么翻译……

@captainblue2013 那到底是蛋疼菊紧还是一泻千里畅快万分?

@hxyfj 没设置就使用浏览器默认配置

回到顶部