前端缓存之HTTP缓存(强缓存+协商缓存)

170 篇文章 3 订阅
6 篇文章 0 订阅

HTTP缓存

HTTP Cache是我们开发中接触最多的缓存, 它分为强缓存和协商缓存

  1. 强缓存: 直接从本地副本对比获取, 不去请求服务器, 返回的状态码是200
  2. 协商缓存: 会去服务器对比, 若没改变才直接读取本地缓存, 返回的状态码是304

(一)、强缓存

强缓存主要包括expirescache-control

1、expires

expiresHTTP1.0中定义的缓存字段。当我们请求一个资源, 服务器返回时, 可以在Response Headers中增加expires字段表示资源的到期时间

expires: Thu, 03 Jan 2019 11:43:04 GMT

它是一个时间戳(准确点应该叫格林尼治时间), 当客户端再次请求该资源的时候, 会把客户端时间与该时间戳进行对比, 如果大于该时间戳则已过期, 否则直接使用该缓存资源

但是, 有个大问题, 发送请求时是使用的客户端时间去对比。一是客户端和服务端时间可能快慢不一致, 另一方面是客户端的时间是可以自行修改的(比如浏览器是跟随系统时间的, 修改系统时间会影响到), 所以不一定满足预期

2、cache-control

正由于上面说的可能存在的问题, HTTP1.1新增了cache-control字段来解决该问题, 所以当cache-controlexpires都存在时, cache-control优先级更高。该字段是一个时间长度, 单位秒, 表示该资源过了多少秒后失效。当客户端请求资源的时候, 发现该资源还在有效时间内则使用该缓存, 它不依赖客户端时间。cache-control主要有max-ages-maxagepublicprivateno-cacheno-store等值

cache-control: public, max-age=3600, s-maxage=3600
  1. max-ages-maxage

两者是cache-control的主要手段, 它们是一个数字, 表示资源过了多少秒后变为无效。在浏览器中, max-ages-maxage都起作用, 而且s-maxage的优先级高于max-age。在代理服务器中, 只有s-maxage起作用。可以通过设置max-age为0表示立即过期来向服务器请求资源
2. publicprivate

public表示该资源可以被所有客户端和代理服务器缓存, 而private表示该资源仅能客户端缓存。默认值是private, 当设置了s-maxage的时候表示允许代理服务器缓存, 相当于public
3. no-cacheno-store

no-cache表示的是不直接询问浏览器缓存情况, 而是去向服务器验证当前资源是否更新(即协商缓存)。no-store则更狠, 完全不使用缓存策略, 不缓存请求或响应的任何内容, 直接向服务器请求更新。由于两者都不考虑缓存情况而是直接与服务器交互, 所以当no-cacheno-store存在时会直接忽略max-age

3、pragma

既然讲到了no-cacheno-store, 就顺便把pragma也讲了。它的值有no-cacheno-store, 表示意思同cache-control, 优先级高于cache-controlexpires, 即三者同时出现时, 先看pragma->cache-control->expires

pragma: no-cache

(二)、协商缓存

上面的expirescache-control都会访问本地缓存直接验证看是否过期, 如果没过期直接使用本地缓存, 返回200。但如果设置了no-cacheno-store则本地缓存会被忽略, 会去请求服务器验证资源是否更新, 如果没更新才继续使用本地缓存, 此时返回的是304, 这就是协商缓存。协商缓存主要包括last-modifiedETag

1、last-modified

last-modified记录资源最后修改的时间。启用后, 请求资源之后的响应头会增加一个last-modified字段, 如下:

last-modified: Thu, 20 Dec 2018 11:36:00 GMT

当再次请求该资源时, 请求头中会带有if-modified-since字段, 值是之前返回的last-modified的值, 如: if-modified-since: Thu, 20 Dec 2018 11:36:00 GMT。服务端会对比该字段和资源的最后修改时间, 若一致则证明没有被修改, 告知浏览器可直接使用缓存并返回304; 若不一致则直接返回修改后的资源, 并修改last-modified为新的值

last-modified有以下两个缺点:

  • 只要编辑了, 不管内容是否真的有改变, 都会以这最后修改的时间作为判断依据, 当成新资源返回, 从而导致了没必要的请求相应, 而这正是缓存本来的作用即避免没必要的请求
  • 时间的精确度只能到秒, 如果在一秒内的修改是检测不到更新的, 仍会告知浏览器使用旧的缓存

2、ETag

为了解决last-modified上述问题, 有了ETagETag会基于资源的内容编码生成一串唯一的标识字符串, 只要内容不同, 就会生成不同的ETag。启动ETag之后, 请求资源后的响应返回会增加一个ETag字段, 如下:

ETag: "ALJlkaasdkljasldjLSAJDakl_"

当再次请求该资源时, 请求头会带有if-none-match字段, 值是之前返回的ETag值, 如: if-none-match: "ALJlkaasdkljasldjLSAJDakl_"。服务端会根据该资源当前的内容生成对应的标识字符串和该字段进行对比, 若一致则代表未改变可直接使用本地缓存并返回304; 若不一致则返回新的资源(状态码200)并修改返回的ETag字段为新的值。

可以看到ETaglast-modified更加精准地感知了变化, 所以ETag优先级也更高。不过从上面也可以看出ETag的存在的问题, 就是每次生成标识字符串会增加服务器的开销。所以你要如何使用last-modifiedETag还需要根据具体需求进行权衡

(三)、访问刷新分析

我们将访问和刷新分为以下三种情况:

  • 标签进入、输入url回车进入
  • 按刷新按钮、F5 刷新、网页右键“重新加载”
  • ctrl + F5 强制刷新

假设当前有这么一个 index 页面,返回的响应信息如下:

cache-control: max-age=72000
expires: Tue, 20 Nov 2018 20:41:14 GMT
last-modified: Tue, 20 Nov 2018 00:41:14 GMT

1、标签进入、输入url回车进入

这种情况下会根据实际设计的缓存策略去判断。

  1. 由于该例没有设置no-cacheno-store, 所以默认先走强缓存路线。根据cache-control(expires优先级低)判断缓存是否过期, 若没有过期则此时返回200(from cache)
  2. 若本地缓存已经过期再走协商缓存路线, 根据之前last-modified值去服务器对比, 若这个时间之后没有改过则去读取本地缓存, 返回304(not modified)
  3. 否则返回新的资源, 状态码200(ok), 并更新返回响应的last-modified

2、按刷新按钮、F5 刷新、网页右键“重新加载”

这种情况下, 实际是浏览器将cache-controlmax-age直接设置成了0, 让缓存立即过期, 直接走协商缓存路线。发送的请求头如下:

cache-control: max-age=0
if-modified-since: Tue, 20 Nov 2018 00:41:14 GMT

3、ctrl + F5 强制刷新

强制刷新的情况下, 浏览器会强行设置no-cache, 强制获取最新的资源, 就连if-modified-since等其它缓存协议字段都会被吃掉。此时发送的请求头如下:

cache-control: no-cache
pragma: no-cache


参考链接:https://www.jianshu.com/p/fb59c770160c

欢迎大家关注我的公众号,有很多关于前端的内容哦
QQ:505417246
WX:18331092918
公众号:Code程序人生
B站账号:LuckyRay123
个人博客:http://rayblog.ltd/

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值