HTTP 缓存机制

Posted by Rimin on 2019-06-13

在整个大的应用体系中,缓存是节省流量,快捷高效的一环。

缓存的分类

  • 源服务端缓存:比如 Nginx、Apache
  • 网络中缓存: 代理服务器缓存(共享缓存), 反向代理服务器缓存(网关缓存负载均衡, CDN)
  • 浏览器缓存:HTTP 缓存、indexDB、cookie、localstorage 等等

优点&缺点

  • 使用缓存的优点:

    • 请求更快
    • 节省带宽
    • 降低服务器压力
  • 缺点

    • 网站管理员特别希望知道网站的一举一动,比方说多少人访问,访问时间,而缓存会“隐藏”他们的用户,他们就无从得知到底谁访问了这个站点
      (解决方法之一:可以选择页面上的一个小元素(或页面本身),然后给这个元素一个适当的头信息使它是不可缓存。比如,你可以在每一个页面上引用一个1像素×1像素的不可缓存(如scr地址后面加个随机数Add)的透明图片。Referer头信息将会包含调用它的页面信息。即使这样也不能给出你用户的精确统计,并且对通过互联网访问的用户也不是很友好:产生不必要的流量,并强迫用户等待未被缓存的内容从网络上下载回来)
    • 无法及时更新

http缓存机制

规则 消息包头 值/示例 类型 作用 缺点/局限/注意
新鲜度 Expires Mon, 15 Aug 2016 03:56:47 GMT response 启用缓存和定义缓存时间。告诉浏览器资源缓存过期时间,如果还没过该时间点则不发请求 (http1.0)该时间是相对服务器的,因此存在客户端和服务端时间上不一致的问题。
Cache-Control public response 任何路径的缓存者(本地缓存、代理服务器)均可缓存
private response 指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。
no-cache response 告诉浏览器忽略资源的缓存副本,强制每次请求直接发送给服务器,拉取资源,但不是“不缓存”
no-store response 强制缓存在任何情况下都不要保留任何副本
max-age response 指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。上次缓存时间(客户端的)+max-age(64200s)<客户端当前时间
min-fresh response 指示客户机可以接收响应时间小于当前时间加上指定时间的响应
max-stale response 指示客户机可以接收超出超时期间的响应消息
Pragma no-cache response http1.0中存在的字段,在http1.1已被抛弃,使用Cache-Control替代,但为了做http协议的向下兼容,很多网站依旧会带上这个字段
校验值 Last-Modified Mon, 15 Aug 2016 03:56:47 GMT response 标示这个响应资源的最后修改时间 只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间 。 如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存,有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形(无法使用缓存)可以使用ETag
If-Modified-Since Mon, 15 Aug 2016 03:56:47 GMT request 当资源过期时(使用Cache-Control标识的max-age),其值为上次响应头的Last-Modified值,再次向web服务器请求时带上头If-Modified-Since。web服务器收到请求后发现有头If-Modified-Since则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),包括更新Last-Modified的值,HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304(无需包体,节省浏览),告知浏览器继续使用所保存的cache 要配合Cache-Control使用
Etag “fd56273325a2114818df4f29a628226d” response 告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)如果有 Etag 字段,那么浏览器就会将本次缓存写入硬盘中,之后的缓存是from disk cache
If-None-Match “fd56273325a2114818df4f29a628226d” request 当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match(Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。 Etag/If-None-Match也要配合Cache-Control使用。需要注意的是分布式系统里多台机器间文件的last-modified必须保持一致,以免负载均衡到不同机器导致比对失败,Yahoo建议分布式系统尽量关闭掉Etag(每台机器生成的etag都会不一样,因为除了 last-modified、inode 也很难保持一致)。

浏览器缓存机制

  1. 分类:

    • 强缓存: 浏览器在加载资源时,先根据这个资源的一些http header判断它是否命中强缓存,强缓存如果命中,浏览器直接从自己的缓存中读取资源,不会发请求到服务器。比如某个css文件,如果浏览器在加载它所在的网页时,这个css文件的缓存配置命中了强缓存,浏览器就直接从缓存中加载这个css,连请求都不会发送到网页所在服务器。
    • 协商缓存: 当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外一些http header验证这个资源是否命中协商缓存,如果协商缓存命中,服务器会将这个请求返回(304),但是不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源,于是浏览器就又会从自己的缓存中去加载这个资源;若未命中请求,则将资源返回客户端,并更新本地缓存数据(200)。
    • 强缓存与协商缓存区别:强缓存不发请求到服务器,协商缓存会发请求到服务器。
  2. 设置缓存

1
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">

但是 仅有IE才能识别这段meta标签含义,其它主流浏览器仅识别“Cache-Control: no-store”的meta标签。

  1. 浏览器缓存位置

    1. Service Worker: 运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用 Service Worker的话,传输协议必须为 HTTPS
    2. Memory Cache (读取内存中的数据)
    3. Disk Cache
    4. Push Cache: 是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。并且缓存时间也很短暂,只在会话(Session)中存在,一旦会话结束就被释放
    5. 网络请求
  2. 机制

  • 第一次请求:

image

  • 再次发送请求时:

image

相关问题

  • 我的图片缓存一个月后才到期,我现在就想变动怎么办?

最有效的方法是修改链接,这样会从源服务器获取完整的新内容。请记住,调用图片的这个页面也会被缓存的,正因如此,我们需要让图片以及其他类似的静态资源易缓存,而页面呢可以随着自身的改变(例如改变了一个图片的URL地址Add)即时更新。

大公司的静态资源优化方案,基本上要实现这么几个东西:

  1. 配置超长时间的本地缓存 —— 节省带宽,提高性能
  2. 采用内容摘要作为缓存更新依据 —— 精确的缓存控制(对于修改的静态文件,资源,改变它的url或者说文件名)
  3. 静态资源CDN部署 —— 优化网络请求
  4. 更新资源发布路径实现非覆盖式发布 —— 平滑升级(先部署页面,再部署资源还是先部署资源,再部署页面问题)

我们可以将所有前端静态资源开启永久强缓存,每次版本发布都可以首先让静态资源全量上线,再进一步上线模板或者页面文件,再也不用担心各种缓存和时间间隙的问题了!

  • 我的页面是密码保护的,代理缓存是怎么处理的?

  • 如果人们通过缓存访问我的网站,我应该担心安全吗?
    (答: SSL页面不会被代理服务器缓存,所以这个你不需要担心。但是,代理服务器就好非SSL页面请求以及URL抓取这口,你懂的,这是不安全的。无良的管理员可能就会收集网站用户的信息,尤其在URL中)

参考:

详解web缓存

浏览器 HTTP 协议缓存机制详解

Web 开发人员需知的 Web 缓存知识

大公司里怎样开发和部署前端代码?