通过 Internet 获取资源既缓慢, 成本又高为此, Http 协议里包含了控制缓存的部分, 以使 Http 客户端可以缓存和重用以前获取的资源, 从而优化性能, 提升体验虽然 Http 中关于缓存控制的部分, 随着协议演进, 有一些变化但我觉着, 作为后端程序员, 在开发 web 服务时, 只需要关注请求头 If-None-Match 响应头 ETag 响应头 Cache-Control 就足够了因为这三个 Http 头就可以满足你的需求, 并且, 当今绝大多数的浏览器, 都支持这三个 Http 头我们所要做的就是, 确保每个服务器响应都提供正确的 HTTP 头指令, 以指导浏览器何时可以缓存响应以及可以缓存多久
缓存在哪儿?
上图中有三个角色, 浏览器 Web 代理和服务器, 如图所示 HTTP 缓存存在于浏览器和 Web 代理中当然在服务器内部, 也存在着各种缓存, 但这已经不是本文要讨论的 Http 缓存了所谓的 Http 缓存控制, 就是一种约定, 通过设置不同的响应头 Cache-Control 来控制浏览器和 Web 代理对缓存的使用策略, 通过设置请求头 If-None-Match 和响应头 ETag, 来对缓存的有效性进行验证
响应头 ETag
ETag 全称 Entity Tag, 用来标识一个资源在具体的实现中, ETag 可以是资源的 hash 值, 也可以是一个内部维护的版本号但不管怎样, ETag 应该能反映出资源内容的变化, 这是 Http 缓存可以正常工作的基础
如上例中所展示的, 服务器在返回响应时, 通常会在 Http 头中包含一些关于响应的元数据信息, 其中, ETag 就是其中一个, 本例中返回了值为 x1323ddx 的 ETag 当资源 / file 的内容发生变化时, 服务器应当返回不同的 ETag
请求头 If-None-Match
对于同一个资源, 比如上一例中的 / file, 在进行了一次请求之后, 浏览器就已经有了 / file 的一个版本的内容, 和这个版本的 ETag, 当下次用户再需要这个资源, 浏览器再次向服务器请求的时候, 可以利用请求头 If-None-Match 来告诉服务器自己已经有个 ETag 为 x1323ddx 的 / file, 这样, 如果服务器上的 / file 没有变化, 也就是说服务器上的 / file 的 ETag 也是 x1323ddx 的话, 服务器就不会再返回 / file 的内容, 而是返回一个 304 的响应, 告诉浏览器该资源没有变化, 缓存有效
如上例中所示, 在使用了 If-None-Match 之后, 服务器只需要很小的响应就可以达到相同的结果, 从而优化了性能
响应头 Cache-Control
每个资源都可以通过 Http 头 Cache-Control 来定义自己的缓存策略, Cache-Control 控制谁在什么条件下可以缓存响应以及可以缓存多久 最快的请求是不必与服务器进行通信的请求: 通过响应的本地副本, 我们可以避免所有的网络延迟以及数据传输的数据成本为此, HTTP 规范允许服务器返回一系列不同的 Cache-Control 指令, 控制浏览器或者其他中继缓存如何缓存某个响应以及缓存多长时间
Cache-Control 头在 HTTP/1.1 规范中定义, 取代了之前用来定义响应缓存策略的头 (例如 Expires) 当前的所有浏览器都支持 Cache-Control, 因此, 使用它就够了
以下我来介绍可以再 Cache-Control 中设置的常用指令
max-age
该指令指定从当前请求开始, 允许获取的响应被重用的最长时间(单位为秒例如: Cache-Control:max-age=60 表示响应可以再缓存和重用 60 秒需要注意的是, 在 max-age 指定的时间之内, 浏览器不会向服务器发送任何请求, 包括验证缓存是否有效的请求, 也就是说, 如果在这段时间之内, 服务器上的资源发生了变化, 那么浏览器将不能得到通知, 而使用老版本的资源所以在设置缓存时间的长度时, 需要慎重
public 和 private
如果设置了 public, 表示该响应可以再浏览器或者任何中继的 Web 代理中缓存, public 是默认值, 即 Cache-Control:max-age=60 等同于 Cache-Control:public, max-age=60
在服务器设置了 private 比如 Cache-Control:private, max-age=60 的情况下, 表示只有用户的浏览器可以缓存 private 响应, 不允许任何中继 Web 代理对其进行缓存 例如, 用户浏览器可以缓存包含用户私人信息的 html 网页, 但是 CDN 不能缓存
no-cache
如果服务器在响应中设置了 no-cache 即 Cache-Control:no-cache, 那么浏览器在使用缓存的资源之前, 必须先与服务器确认返回的响应是否被更改, 如果资源未被更改, 可以避免下载这个验证之前的响应是否被修改, 就是通过上面介绍的请求头 If-None-match 和响应头 ETag 来实现的
需要注意的是, no-cache 这个名字有一点误导设置了 no-cache 之后, 并不是说浏览器就不再缓存数据, 只是浏览器在使用缓存数据时, 需要先确认一下数据是否还跟服务器保持一致如果设置了 no-cache, 而 ETag 的实现没有反应出资源的变化, 那就会导致浏览器的缓存数据一直得不到更新的情况
no-store
如果服务器在响应中设置了 no-store 即 Cache-Control:no-store, 那么浏览器和任何中继的 Web 代理, 都不会存储这次相应的数据当下次请求该资源时, 浏览器只能重新请求服务器, 重新从服务器读取资源
怎样决定一个资源的 Cache-Control 策略呢?
下面这个流程图, 可以帮到你
来源: http://www.codeceo.com/article/http-cache-backend-programmer.html