一张图理解Http缓存

参阅了一些浏览器缓存的资料,本文通过一张图来归纳总结其过程。

浏览器第一次向一个web服务器发起http请求后,服务器会返回请求的资源,并且在响应头中添加一些有关缓存的字段如:Cache-ControlExpiresLast-ModifiedETagDate等等。之后浏览器再向该服务器请求该资源就可以视情况使用强缓存协商缓存

  • 强缓存:浏览器直接从本地缓存中获取数据,不与服务器进行交互。
  • 协商缓存:浏览器发送请求到服务器,服务器判定是否可使用本地缓存。
  • 联系与区别:两种缓存方式最终使用的都是本地缓存;前者无需与服务器交互,后者需要。

下面假定浏览器已经访问了服务器,服务器返回了缓存相关的头部字段且浏览器已对相关资源做好缓存。通过下图来分析强缓存和协商缓存:

clipboard.png

强缓存

如图红线所示的过程代表强缓存。用户发起了一个http请求后,浏览器发现先本地已有所请求资源的缓存,便开始检查缓存是否过期。有两个http头部字段控制缓存的有效期:ExpiresCache-Control,浏览器是根据以下两步来判定缓存是否过期的:

  1. 查看缓存是否有Cache-Controls-maxagemax-age指令,若有,则使用响应报文生成时间Date + s-maxage/max-age获得过期时间,再与当前时间进行对比(s-maxage适用于多用户使用的公共缓存服务器);
  2. 如果没有Cache-Controls-maxagemax-age指令,则比较Expires中的过期时间与当前时间。Expires是一个绝对时间。

注意,在HTTP/1.1中,当首部字段Cache-Control有指定s-maxagemax-age指令,比起首部字段Expires,会优先处理s-maxagemax-age

另外下面列几个Cache-Control的常用指令:

  • no-cache:含义是不使用本地缓存,需要使用协商缓存,也就是先与服务器确认缓存是否可用。
  • no-store:禁用缓存。
  • public:表明其他用户也可使用缓存,适用于公共缓存服务器的情况。
  • private:表明只有特定用户才能使用缓存,适用于公共缓存服务器的情况。

经过上述两步判断后,若缓存未过期,返回状态码为200,则直接从本地读取缓存,这就完成了整个强缓存过程;如果缓存过期,则进入协商缓存或服务器返回新资源过程。

协商缓存

当浏览器发现缓存过期后,缓存并不一定不能使用了,因为服务器端的资源可能仍然没有改变,所以需要与服务器协商,让服务器判断本地缓存是否还能使用。此时浏览器会判断缓存中是否有ETagLast-Modified字段,如果没有,则发起一个http请求,服务器根据请求返回资源;如果有这两个字段,则在请求头中添加If-None-Match字段(有ETag字段的话添加)、If-Modified-Since字段(有Last-Modified字段的话添加)。注意:如果同时发送If-None-MatchIf-Modified-Since字段,服务器只要比较If-None-MatchETag的内容是否一致即可;如果内容一致,服务器认为缓存仍然可用,则返回状态码304,浏览器直接读取本地缓存,这就完成了协商缓存的过程,也就是图中的蓝线;如果内容不一致,则视情况返回其他状态码,并返回所请求资源。下面详细解释下这个过程:

1.ETagIf-None-Match

二者的值都是服务器为每份资源分配的唯一标识字符串。

  • 浏览器请求资源,服务器会在响应报文头中加入ETag字段。资源更新时,服务器端的ETag值也随之更新;
  • 浏览器再次请求资源时,会在请求报文头中添加If-None-Match字段,它的值就是上次响应报文中的ETag的值;
  • 服务器会比对ETagIf-None-Match的值是否一致,如果不一致,服务器则接受请求,返回更新后的资源;如果一致,表明资源未更新,则返回状态码为304的响应,可继续使用本地缓存,要注意的是,此时响应头会加上ETag字段,即使它没有变化。

2.Last-ModifiedIf-Modified-Since

二者的值都是GMT格式的时间字符串。

  • 浏览器第一次向服务器请求资源后,服务器会在响应头中加上Last-Modified字段,表明该资源最后一次的修改时间;
  • 浏览器再次请求该资源时,会在请求报文头中添加If-Modified-Since字段,它的值就是上次服务器响应报文中的Last-Modified的值;
  • 服务器会比对Last-ModifiedIf-Modified-Since的值是否一致,如果不一致,服务器则接受请求,返回更新后的资源;如果一致,表明资源未更新,则返回状态码为304的响应,可继续使用本地缓存,与ETag不同的是:此时响应头中不会再添加Last-Modified字段。

3.ETag较之Last-Modified的优势

以下内容引用于:http协商缓存VS强缓存

你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要ETag呢?HTTP1.1ETag的出现主要是为了解决几个Last-Modified比较难解决的问题:

  • 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET
  • 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
  • 某些服务器不能精确的得到文件的最后修改时间。

这时,利用ETag能够更加准确的控制缓存,因为ETag是服务器自动生成的资源在服务器端的唯一标识符,资源每次变动,都会生成新的ETag值。Last-ModifiedETag是可以一起使用的,但服务器会优先验证ETag

用户行为

最后附一张图说明用户行为对浏览器缓存的影响:
clipboard.png


前端之路
前端的学习记录
1.4k 声望
1k 粉丝
0 条评论
推荐阅读
蚂蚁金服AntV-S2重磅发布
S2 是 AntV 团队推出的数据表可视化引擎,旨在提供高性能、易扩展、美观、易用的多维表格。不仅有丰富的分析表格形态,还内置丰富的交互能力, 帮助用户更好地看数和做决策。 ​

Leon阅读 3.3k

封面图
Chrome 103支持使用本地字体,纯前端导出PDF优化
在前端导出PDF,解决中文乱码一直是一个头疼的问题。要解决这个问题,需要将ttf等字体文件内容注册到页面PDF生成器中。但是之前网页是没有权限直接获取客户机器字体文件,这时就需要从服务器下载字体文件或者提示...

葡萄城技术团队3阅读 13.9k

HTTP,WebSocket 和 聊天室
在涉及到网络层面的相关内容时,不免会联系到 HTTP、TCP、WebSocket 等,但相信大部分人都并不是很清楚其中的一些关系和概念,特别是需要你去做语言表述时,网上有不少优秀的资料和文章,但知识仍需要自己去消化...

熊的猫3阅读 217

封面图
各开发语言DNS缓存配置建议
作者:翟贺龙一、背景在计算机领域,涉及性能优化动作时首先应被考虑的原则之一便是使用缓存,合理的数据缓存机制能够带来以下收益:1.缩短数据获取路径,热点数据就近缓存以便后续快速读取,从而明显提升处理效...

京东云开发者3阅读 382

封面图
深入理解redis——缓存双写一致性之更新策略探讨
1.Redis缓存双写一致性我们都知道,只要我们使用redis,就会遇到缓存与数据库的双存储双写,那么只要是双写,就一定会有数据一致性问题,为了保证双写一致性,我们要先动redis还是mysql?

苏凌峰阅读 2.7k

基于QUIC协议的HTTP/3,你了解多少?
前言了解一下HTTP发展史:HTTP/0.9-HTTP/1.0-HTTP/1.1-HTTP/2.0多个TCP连接 {代码...} Keep-alive {代码...} 管线化 {代码...} 多路复用 {代码...} {代码...} 并行多路复用的请求和响应不会相互阻塞尽管传输多个...

Henryk2阅读 1.2k评论 1

gitlab-ce将https修改为http
索性我们禁用gitlab的https功能,将期恢复为http。后期我们再在部署一个nginx进行数据转发,然后在nginx上起用https并设置证书。这样应该就规避了gitlab的证书错误问题。

myskies1阅读 645

1.4k 声望
1k 粉丝
宣传栏