前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >强缓存与协商缓存

强缓存与协商缓存

作者头像
WindrunnerMax
发布2020-08-27 10:51:59
9440
发布2020-08-27 10:51:59
举报
文章被收录于专栏:Czy‘s BlogCzy‘s Blog

强缓存与协商缓存

浏览器缓存是浏览器在本地磁盘对用户最近请求过的资源进行存储,当访问者再次访问同一资源时,浏览器就可以直接从本地磁盘加载资源,通过缓存的方式就可以减少与服务器的数据传输,减少服务器的负担,加快页面响应速度等。

描述

良好的缓存策略可以降低资源的重复加载提高网页的整体加载速度,通常浏览器缓存策略分为强缓存和协商缓存。常见的HTTP缓存只能存储GET响应,对于其他类型的响应则不会进行缓存。 理论上来讲,当一个资源被缓存存储后,该资源应该可以被永久存储在缓存中,由于缓存只有有限的空间用于存储资源副本,所以缓存会定期地将一些副本删除,这个过程叫做缓存驱逐。另一方面,当服务器上面的资源进行了更新,那么缓存中的对应资源也应该被更新,由于HTTPC/S模式的协议,服务器更新一个资源时,不可能直接通知客户端更新缓存,所以双方必须为该资源约定一个过期时间,在该过期时间之前,该资源的缓存副本就是新鲜的,当过了过期时间后,该资源的缓存副本则变为陈旧的。驱逐算法用于将陈旧的资源缓存副本替换为新鲜的,注意,一个陈旧的资源缓存副本是不会直接被清除或忽略的,当客户端发起一个请求时,缓存检索到已有一个对应的陈旧资源缓存副本,则缓存会先将此请求附加一个If-None-Match头,然后发给目标服务器,以此来检查该资源副本是否是依然还是算新鲜的,若服务器返回了304 (Not Modified),则表示此资源副本是新鲜的,注意该响应不会有带有实体信息,通过这种方式,可以节省一些带宽。若服务器通过If-None-MatchIf-Modified-Since判断后发现已过期,那么会带有该资源的实体内容返回。对上面的请求过程可以概括如下:

  • 浏览器在发起对于资源的请求时,会首先检查本地是否存在缓存,如果存在缓存则通过expirescache-control检查缓存是否过期,如果命中缓存且缓存未过期,则直接使用本地缓存。
  • 本地缓存未命中,则浏览器向服务器发送一个协商请求,通过last-modifiedetag验证资源是否命中协商缓存,如果命中则服务器会将这个请求响应为304,但是不会返回这个资源的数据,依然是从缓存中读取资源,如果未命中则会携带资源返回且响应为200

强缓存

强缓存是通过ExpiresCache-Control来控制缓存在本地的有效期。

Expires

ExpiresHTTP 1.0提出的一个表示资源过期时间的Header,它描述的是一个绝对时间,由服务器返回。Expires受限于本地时间,如果修改了本地时间,可能会造成缓存失效.对于资源的请求,如果在Expires之内,则浏览器会直接读取缓存,不再请求服务器。

代码语言:javascript
复制
Expires: Sun, 14 Jun 2020 02:50:57 GMT

Cache-Control

Cache-Control出现于HTTP 1.1,优先级高于Expires,表示的是相对时间,请求头和响应头都支持这个属性,通过它提供的不同的值来定义缓存策略。

代码语言:javascript
复制
Cache-Control: max-age=300
  • Cache-Control: no-store: 缓存中不得存储任何关于客户端请求和服务端响应的内容,每次由客户端发起的请求都会下载完整的响应内容。
  • Cache-Control: no-cache: 缓存中会存储服务端响应的内容,只是在与服务端进行新鲜度再验证之前,该缓存不能够提供给浏览器使用。简单来说,就是浏览器会将服务端响应的资源进行缓存,但是在每次请求时,缓存都要向服务端评估缓存响应的有效性,协商缓存是否可用,根据响应是304还是200判断是使用本地缓存资源还是使用服务器响应的资源。
  • Cache-Control: public || private: public表示该响应可以被任何中间人比如中间代理、CDN等缓存。默认响应为privateprivate表示该响应是专用的,中间人不能缓存此响应,该响应只能应用于浏览器私有缓存中。
  • Cache-Control: max-age=31536000: 响应为最大的过期时间,其指令是max-age=<seconds>,表示资源能够被缓存即保持新鲜的最大时间,max-age是距离请求发起的时间的秒数。
  • Cache-Control: must-revalidate: 当使用了must-revalidate指令,那就意味着缓存在考虑使用一个陈旧的资源时,必须先验证它的状态,已过期的缓存将不被使用。在正常情况下是没有必要使用这个指令的,因为在强缓存过期的情况下会进行协商缓存,但是HTTP规范是允许客户端在某些特殊情况下直接使用过期缓存的,比如校验请求发送失败的时候,还比如有配置一些特殊指令stale-while-revalidatestale-if-error等的时候,must-revalidate指令就是让缓存在过期后的任何情况下都必须重新验证。

协商缓存

当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的HTTP状态为304 (Not Modified),该请求不携带实体数据,若未命中,则返回200并携带资源实体数据。协商缓存是利用的是Last-Modified,If-Modified-SinceETag、If-None-Match这两对Header来管理的。

Last-Modified If-Modified-Since

Last-Modified,If-Modified-SinceHTTP 1.0引入的,Last-Modified表示本地文件最后修改日期,浏览器会在请求头加上If-Modified-Since即上次响应的Last-Modified的值,询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来,但是如果在本地打开缓存文件,就会造成Last-Modified被修改,所以在HTTP 1.1出现了ETag

ETag If-None-Match

Etag就像一个指纹,资源变化都会导致ETag变化,跟最后修改时间没有关系,ETag可以保证每一个资源是唯一的,If-None-Match的请求头字段会将上次返回的Etag发送给服务器,询问该资源的Etag是否有更新,有变动就会发送新的资源回来。ETag的优先级比Last-Modified更高,具体使用ETag主要出于下面几种情况考虑:

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

每日一题

代码语言:javascript
复制
https://github.com/WindrunnerMax/EveryDay

参考

代码语言:javascript
复制
https://zhuanlan.zhihu.com/p/60357719
https://www.jianshu.com/p/9c95db596df5
https://segmentfault.com/a/1190000008956069
https://github.com/amandakelake/blog/issues/41
https://juejin.im/post/5ccfccaff265da03ab233bf5
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-06-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 强缓存与协商缓存
    • 描述
      • 强缓存
        • Expires
        • Cache-Control
      • 协商缓存
        • Last-Modified If-Modified-Since
        • ETag If-None-Match
      • 每日一题
        • 参考
        相关产品与服务
        内容分发网络 CDN
        内容分发网络(Content Delivery Network,CDN)通过将站点内容发布至遍布全球的海量加速节点,使其用户可就近获取所需内容,避免因网络拥堵、跨运营商、跨地域、跨境等因素带来的网络不稳定、访问延迟高等问题,有效提升下载速度、降低响应时间,提供流畅的用户体验。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档