「MISC」HTTP 缓存控制

如今的Web应用愈来愈复杂,体验愈来愈好。相应的,资源文件也愈来愈大,若是能让客户端在资源没更新的状况下,直接取用缓存的数据,那么不只资源加载的更快,服务器压力更小,也为绿色地球作出了一份贡献。程序员

程序员向来是追求最优,在设法缓存静态资源之后,你们又找到了一些方法来缓存动态生成的内容。看来程序员们都是环境保护主义者(笑。缓存

从HTTP/1.0-HTTP/1.1,一共产生了3种控制缓存的方法:服务器

  • Expires(响应头,HTTP/1.0)
  • Cache-Control(响应头,HTTP/1.1)代理

    - Last-Modified(响应头),If-Modified-Since(请求头)
    - Etag(响应头),If-None-Match(请求头)

以上就是HTTP控制缓存的方法。code

除了这些,在第二个还有If-Unmodified-Since,第三个还有If-Match。但这两个响应头不是为了控制缓存,而是为了确认修改的资源的一致性。以后会介绍。资源

HTTP/1.0

Expires

Expires: <http-date>

其中 <http-date> 的格式以下:io

Date: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
Example: Fri, 03 Nov 2017 03:22:39 GMT

当设置了Expires后,客户端在此日期以前都不会去请求服务器,而是直接从缓存中取。
不过这样也有一个问题:若是彻底不去请求服务器的话,在资源过时以前若是资源有更新,客户端仍是使用着以前的资源。因此就产生了下面更加高级的缓存控制方法(第3、第四项方法)。ast

不过还有一个方法能解决这个问题:将资源的Expires设置为一个足够长的时间,而资源名为资源的Hash值,这样资源更新了之后,也使用的是不一样的名称。那么就不存在上面的问题了。date

HTTP/1.1

Cache-Control

Expires只能设置具体的日期,这样的话,若是客户端与服务器的时间不一致,会致使缓存时间不正确,还有可能直接致使缓存失效。语法

HTTP/1.1的Cache-Control配合If-Modified-Since或If-None-Match则完美的解决了这个问题。

Cache-Control比较经常使用的指令以下:

  • 可缓存性

    • public: 响应可被任意缓存
    • private: 响应只能被客户端缓存,不能被中间节点(代理、CDN等)缓存
    • no-cache: 中间节点必须向原始服务器去验证缓存有效性。若是自己是原始服务器,则向本身确认
    • only-if-cached: 中间节点直接使用已存在的缓存来确认有效性,不向原始服务器确认。若自己是原始服务器,则此指令没有效果。
  • 过时控制

    • max-age=<seconds>: 指定相对于请求时间的过时时间,以秒为单位。
  • 再验证

    • must-revalidation: 缓存过时后必须向服务器确认缓存是否有效
  • 其余

    • no-store: 忽略缓存的存在,直接向服务器请求最新的资源。

上面列表中向服务器确认缓存是否有效的技术手段就是下文介绍的 Last-Modified/If-Modified-SinceETag/If-None-Match

Last-Modified / If-Modified-Since

Last-Modified: <http-date>

Last-Modified头是服务器告诉客户端此资源的最后修改时间,客户端则会将资源和这个时间都储存起来。以后,根据Cache-Control的指令,若是须要同服务器确认资源的有效性的时候则会将这个时间放在If-Modified-Since头中,供服务器进行比较,是返回304仍是200。

If-Modified-Since头只会在GET和HEAD请求被附加进请求头。

If-Unmodified-Since

If-Unmodified-Since: <http-date>

通常来讲在PUT, POST等方法使用,表示该次请求更新的资源的日期为<http-date>,若是服务器检测到现存资源的日期不为<http-date>(即已经被其余的方式更新了),则会失败并返回412。

ETag / If-None-Match

ETag: W/"<etag_value>"
ETag: "<etag_value>"
If-None-Match: "<etag_value>"[, "<etag_value>"...]
If-None-Match: W/"<weak_etag_value>"[, "<weak_etag_value>"]

若是将上面的 Last-Modified / If-Modified-Since 应用在动态的数据上的话,基本上没有可行性。那么就有了此方式的缓存。

在第一次请求的时候,服务器会附带ETag头。ETag的值是根据响应的内容来进行生成的,通常来讲是内容(+其余一些标识的)哈希值。以后,根据Cache-Control的指令,若是须要同服务器确认资源的有效性的时候则会将这个etag_value放在If-None-Match头中,供服务器进行比较,是返回304仍是200。

在ETag的值前若是有W/则表示这是一个弱Etag。弱ETag相等意味着这两个内容语义上是相等的,强ETag相等则表示内容每个字节都相等。

举个弱ETag的例子:返回的数据中带有log信息,而两次返回的数据是相同的,log不一样。

还有一种语法:If-None-Match: *,基本上用在PUT, POST等上,用于上传。表示要求上传的文件在服务器上不存在。

If-Match

If-Match: "<etag_value>"[, "<etag_value>"...]
If-Match: W/"<weak_etag_value>"[, "<weak_etag_value>"]

对于GET, HEAD等请求,若是资源的ETag匹配上If-Match的值,则返回资源,不然返回412。
对于PUT, POST等请求,若是现有资源的Etag匹配上If-Match的值,那么进行写操做,不然失败返回412。

----- 记得点赞 -----

相关文章
相关标签/搜索