阅读 81

从304浅谈http缓存

【一个由304是啥引发的国强是否属于有害垃圾的自我思考】

村头恶霸二狗子:“国强,你说说304是啥吧,这么简单,该不会不会吧?”

涉世未深傻国强:“这题我会,easy!”


1、关于304的定义

一句话定义:Not Modified (服务器端资源未改变,可直接使用客户端未过期的缓存)

在《图解HTTP》中,对304作出的解释是:“该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但因发生请求未满足条件的情况后,直接返回304。304状态码返回时,不包含任何响应的主体部分(带头不带体,减小报文体积,加大传输效率) 。304虽然被划分在3XX中,但是和重定向没有关系”

解释里提及:“因发生请求未满足条件的情况后,直接返回304”。那么这里的【未满足条件的情况】指的又是什么呢?

在浏览器第一次给服务器发送请求后,服务器会在响应头中加上 Last-Modified 这个字段表示该资源将缓存到客户端。客户端再请求一个文件的时候,发现自己缓存的文件有 Last-Modified ,那么在请求头携带 If-Modified-Since 字段,值就是缓存文件的 Last-Modified 。此时服务端只要判断 If-Modified-Since的值和资源最后修改时间就可以确定是返回 304 还是 200。

这时候你会发问,每次都要向服务器咨询缓存有没有过期,未免菜了亿点点了吧?这个时候就要谈及另外一个话题了:强缓存和协商缓存


2、关于强缓存和协商缓存

一句话定义:当浏览器准备向服务器发起请求时,首先会通过校验强缓存是否可用,如果可用则直接使用(此时请求依旧会返回200状态,但并无与服务端交互)。否则进入协议缓存,即发送http请求。

1. 强缓存

强缓存阶段是不需要发送http请求的,这个阶段只需对上次请求的响应头字段进行判断,如果资源还在可用期,直接复用缓存资源。

在HTTP/1.0时代,使用的是Expires,而HTTP/1.1 使用的是Cache-Control。

1.1 Expires

请求头会带一个Expires字段,表示资源过期时间,下次请求时,只需将当前时间与Expires比对,即可获知缓存是否可用

Expires: Wed, 22 Nov 2019 08:41:00 GMT
复制代码

但是存在一个问题就是,Expires是与客户端时间比对,故会存在客户端与服务端时间不一致的情况。故此方法在HTTP/1.1被废弃了

1.2 Cache-Control

在HTTP1.1中,采用了一个非常关键的字段:Cache-Control。这个字段也是存在于服务器返回的响应头中。

它和Expires本质的不同在于它并没有采用“具体的过期时间点” ,而是采用过期时长来控制缓存。对应的字段是max-age。比如:

//表示在3600秒内 可直接使用缓存
Cache-Control:max-age=3600
复制代码

除了max-age外,它还存在其他属性:

  • public:表示客户端和代理服务器都可以缓存。因为通常一个请求可能给要经过不同的代理服务器最后才到达目标服务器,那么结果就是不仅仅浏览器可以缓存数据,中间的任何代理节点都可以进行缓存
  • private:这种情况下就是只有浏览器才能缓存,中间的代理服务器不能缓存
  • no-cache:跳过当前的强缓存,发送http请求,直接进入协商缓存阶段
  • no-store:不进行任何形式的缓存
  • s-maxage:这和max-age长得比较像,但是区别在于s-maxage是针对代理服务器的缓存时间
  • must-revalidate:加上这个字段,一旦缓存过期。就必须回到源服务器验证(因为 HTTP 规范是允许客户端在某些特殊情况下直接使用过期缓存的,比如校验请求发送失败的时候,还比如有配置一些特殊指令(stale-while-revalidatestale-if-error等)的时候)

当Expires和Cache-Control同时存在的时候,Cache-Control会优先考虑

当个强缓存失效了,那么就进入下一阶段——协商缓存

2. 协商缓存

当强缓存失效后,即会想服务器发送请求。除首次发送请求外,后续的请求会在请求头带上一个 缓存tag ,用来校验客户端缓存是否可用

缓存tag大致可分为两种:Last-Modified 和 ETag

2.1 Last-Modified

客户端首次发送请求的时候,服务端会在响应头里带上 Last-Modified,该字段表示资源最后修改时间。当客户端再次请求时,会在请求头带上 If-Modified-Since 字段,这个字段也就是上次请求返回回来的 Last-Modified 的值

服务端在拿到 If-Modified-Since 字段后,与服务器中资源最后修改时间进行比对:

  • 如果 If-Modified-Since 值小于服务器资源最后修改时间,证明资源已经更新。此时将最新的资源与最新的修改时间返回
  • 否则,返回304,告诉客户端缓存可用
2.2 ETag

ETag是根据文件内容,生成一个标识(类似文件哈希),并且将此标识作为文件资源是否更新的依据。

客户端接收到ETag的值,会在下次请求时,将这个值作为If-None-Match这个字段的内容,并放到请求头中,然后发给服务器。

服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对:

  • 如果两者不一样,说明要更新了。服务器返回新的资源,跟常规的HTTP请求响应的流程一样
  • 否则,返回304,告诉客户端缓存可用
2.3 两者对比
  • 在精度上,ETag优于Last-Modified。因为ETag是按照内容给资源上标识,所以能够准确感知资源的变化。而Last-Modified就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况:

    • 编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失败
    • Last-Modified能够感知的单位是秒,如果文件在1秒内改变了多次,那么这时候的Last-Modified并没有体现出修改
  • 在性能上,Last-Modified优于Etag,原因也很简单,Last-Modified仅仅只是记录一个时间点,而ETag需要根据文件的具体内容生成哈希值

  • 另外,如果两种方式都支持的话,服务器会优先考虑ETag


文章分类
前端
文章标签