客户端HTTP缓存的使用-明明白白

本文章转载自知乎文章,链接:https://zhuanlan.zhihu.com/p/147240962?utm_id=0

浏览器缓存概念

浏览器缓存(Brower Caching)是浏览器对之前请求过的文件进行缓存,以便下一次访问时重复使用,节省带宽,提高访问速度,降低服务器压力.
简而言之,就是告诉浏览器在约定的这个时间前,可以直接从缓存中获取资源(representations),而无需跑到服务器去获取。

HTTP Cache
判断浏览器是如何缓存的
第一次请求:
在这里插入图片描述
第二次请求相同网页:
在这里插入图片描述
HTTP 缓存的类别
浏览器缓存分为强缓存协商缓存
强制缓存
代表在已缓存的资源未失效(未过期)的情况下,不会向服务器发送请求,会直接从资源池中读取资源。
缓存规则
对于强制缓存而言,响应头中有两个字段标明了它的缓存规则,一个是Expires,另一个是 Cache - Control。

Expires: Expires的值包含具体的日期和时间,是服务器返回的资源到期时间,即在此时间之前,可以直接从资源池中读取资源,无需再次请求服务器。
例子:

Expires: Wed, 31 Jul 2019 02:58:24 GMT

Cache-Control: Cache-Control 可以被用于请求和响应头中,组合使用多种指令来指定缓存机制。下面列举了比较常用的指令:

  • private:资源只可以被客户端缓存,Cache-Control 的默认值。
  • public:资源可以被客户端和代理服务器缓存。
  • max-age=t:客户端缓存的资源将在t秒后失效,但是会走协商缓存。
  • no-cache:跳过强缓存,需要使用协商缓存来验证资源
  • no-store:不缓存任何资源。
  • s-maxAge:MDN上面说,覆盖max-age或者Expires头,但是仅适用于共享缓存(比如各个代理),私有缓存会忽略它。那么它的使用场景在哪里呢,在stackoverflow里面有人提出

A reverse caching proxy will be able to serve the same resource to any number of clients for as long as s-maxage. The load on the proxy will increase with the number of clients, so it may be worth having the proxy’s single check (s-maxage) be more frequent than the requests from downstream clients (e.g. browsers) (max-age).

也就是说,对于代理缓存服务器而言,尤其在为有众多的客户机提供时,直接使用s-maxage会比频繁检查max-age来得更加省心一点。

private和public的区别在于是否允许中间节点(即代理服务器)进行资源缓存,如果Cache-Control 值设置为public:

客户端 -  代理服务器 - 服务器

中间的代理服务器可以缓存资源,如果下一次再请求同一资源,代理服务器就可以直接把自己缓存的资源返回给客户端,而无需再请求服务器。但如果 Cache-Control 值设置为 private,表明资源只能被当前用户在客户端缓存,属于私有缓存,不能作为共享缓存( 代理服务器缓存的资源可以共享 )。

例子:

Cache-Control: max-age=31536000

例子中,Cache-Control 仅指定了 max-age,所以默认为 private,缓存时间为 31536000 秒( 365天 )。也就是说,在 365 天内再次请求该资源时,都会直接使用资源池中的资源。

Expires与Cache-Control 同时出现

因为Expires 是有问题的,它最大的问题在于对“本地时间”的依赖,如果服务端和客户端的时间设置可能不同,或者我直接手动去把客户端的时间改掉,那么expires将无法到达我们的预期,因此出现Cache-Control来弥补缺陷。

Expires 属于 HTTP/1.0 的产物,而 Cache-Control 属于 HTTP/1.1 的产物,如果服务器同时设置了 Expires 与 Cache-Control,那么以更先进的 Cache-Control 为准。在某些不支持 HTTP/1.1 的环境中,Expires 才能发挥作用,现阶段只是一种兼任性的写法。

强制缓存的弊端

强制缓存的判定标准,主要依据来自于是否超出某个时间或某个时间段,而不关心服务器端资源是否已经更新,这可能会导致加载的资源早已不是服务器最新的内容。

协商缓存

针对强制缓存的弊端,协商缓存需要进行资源对比判断是否可以使用缓存。

客户端第一次请求资源时,服务器会将缓存标识与资源一起返回给客户端,客户端将二者备份至资源池中。当再次请求相同资源时(此时,强制缓存过期,缓存资源还在),客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行验证,如果验证结果为未更新,服务器会返回304,通知客户端可以继续使用缓存资源。

协商缓存的优先级低于强制缓存,因此只有在强制缓存失效后,客户端才会携带缓存标识向服务器发起请求。

缓存和浏览器操作

缓存的重要一环是浏览器,常见浏览器行为对应的缓存行为有哪些呢?

  • 当用户 Ctrl + F5 强制刷新网页时,浏览器直接从服务器加载,跳过强缓存和协商缓存
  • 当用户仅仅敲击 F5 刷新网页时,跳过强缓存,但是仍然会进行协商缓存过程

在这里插入图片描述
缓存规则

不同于强制缓存,协商缓存缓存最重要的是缓存标识的传递。缓存标识在请求头和响应头之间进行传递,具体方式可以分为以下两组:

Last-Modified / If-Modified-Since

当我们第一次发出请求时,Last-Modified 由服务器返回,通知客户端,该资源的最后修改时间。当我们再次请求该资源时,If-Modified-Since 由客户端发送,其保存了 Last-Modified 的值。服务器收到请求后,将 If-Modified-Since 的值与被请求资源的最后修改时间进行比对。若资源的最后修改时间大于 If-Modified-Since 的值,说明资源被修改过,则返回状态码 200 以及最新资源;若资源的最后修改时间小于或等于 If-Modified-Since 的值,说明资源无修改,则返回状态码 304,通知客户端继续使用缓存资源。

例子:

//第二次发出请求时,请求头内容
If-Modified-Since: Mon, 23 Jul 2018 08:29:29 GMT

//第二次发出请求时,响应头内容
Last-Modified: Mon, 23 Jul 2018 08:29:29 GMT

//此时,状态码应该为:
Status Code: 304 Not Modified

ETag / If-None-Match

说说 ETag 会出现的原因?
因为Last-Modified 标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内被多次修改的话,它将不能准确标注文件的修改时间。也要考虑到,一些文件也许会周期性的更改,但是它的内容并不改变,仅仅改变的修改时间,这时候用Last-Modified/If-Modified-Since就不是很合适了。

当我们第一次发出请求时,ETag 由服务器返回,其值为该资源的标签。当我们再次请求该资源时,If-None-Match 由客户端发送,其保存了 ETag 的值。服务器收到请求后,将 If-None-Match 的值与被请求资源的标签进行比对。若资源的标签不等于 If-None-Match 的值,说明资源被修改过,则返回状态码 200 以及最新资源;若资源的标签等于 If-None-Match 的值,说明资源无修改,则返回状态码 304,通知客户端继续使用缓存资源。

ETag / If-None-Match 组合的优先级高于 Last-Modified / If-Modified-Since 组合。

例子:

//第二次发出请求时,请求头内容
If-None-Match: W/"5ce-164c641f628"

//第二次发出请求时,响应头内容
ETag: W/"5ce-164c641f628"

//此时,状态码应该为:
Status Code: 304 Not Modified

**但是注意,大厂一般都不怎么用Etag。**因为大厂多使用负载分担的方式来调度HTTP请求。因此,同一个客户端对同一个页面的多次请求,很可能被分配到不同的服务器来响应,而根据ETag的计算原理,不同的服务器,有可能在资源内容没有变化的情况下,计算出不一样的Etag,而使得缓存失效。

衍生出来的问题

如果该资源文件被强制缓存起来了,并且缓存时间还未过期时,如何判断该文件是否已经被修改了呢?也就是此时的文件是否是最新的我们不得而知。在HTTP规范里面并没有解决这个问题的方案。

答:通过不缓存html,为静态文件添加MD5或者hash标识,解决浏览器无法跳过缓存过期时间主动感知文件变化的问题。因为加上了hash标识,使得每次请求时的路径名不完全相等,也就不能够直接拿本地缓存了,进而去找协商缓存,从而访问服务器。当然加hash标识这一步,现在可以用打包工具来实现。

本文章转载自知乎文章,链接:https://zhuanlan.zhihu.com/p/147240962?utm_id=0

感谢原作者!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值