浏览器的协商缓存与强缓存

浏览器缓存是什么

浏览器将最近请求过的文档存储在本地磁盘,当访问者再次访问同一页面时,浏览器直接从本地磁盘加载文档,而不会重新的请求的行为就是浏览器缓存。

浏览器缓存的优点:

  1. 减少冗余的数据传输,节省网络资源,减少服务器负担
  2. 提升网站的性能,加快客户端加载网页的速度

在前端开发面试中,浏览器缓存是web性能优化面试题中很重要的一个知识点,从而说明浏览器缓存是提升web性能的一大利器。

下图展示了浏览器访问一个有缓存的页面的时候的决策流程。

在这里插入图片描述

浏览器缓存的分类

浏览器缓存主要有两类:强缓存和协商缓存。

发散阅读 HTTP1.0 HTTP1.1 HTTP2.0主要特性对比

一、强缓存:不用请求服务器,直接使用本地缓存,利用http响应头中的Exprires或Cache-Cantrol实现。

Expires或者Cache-Control两个字段表示资源的缓存时间。

Expires 是http1.0时的规范,是服务器返回一个的绝对时间(GMT格式的时间字符串,比如Expires:Mon,18 Oct 2066 23:59:59 GMT),这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。所以,在http1.1中,提出了一个新的response header,就是Cache-Control。

Cache-Control主要是利用该字段的max-age值来进行判断,它是一个相对时间,例如Cache-Control:max-age=3600,代表着资源的有效期是3600秒。cache-control除了该字段外,还有下面几个比较常用的设置值:

  • no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
  • no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。
  • public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。
  • private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。

Cache-Control与Expires可以在服务端配置同时启用,同时启用的时候Cache-Control优先级高。

二、协商缓存:浏览器发现本地有资源的副本,但是不太明确要不要使用,于是去问问服务器。

协商缓存是利用的是两对Header:

  • 第一对:Last-Modified、If-Modified-Since
  • 第二对:ETag、If-None-Match

这两组搭档都是成对出现的,即第一次请求的响应头带上某个字段(Last-Modified或者Etag),则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。

Last-Modify/If-Modify-Since

  1. 浏览器第一次请求一个资源的时候,服务器返回的response header中会加上Last-Modify,标识该资源的最后修改时间,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。
  2. 当浏览器再次请求该资源时,request header中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。
  3. 服务器收到第二次请求时的If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。
  4. 如果命中缓存,则返回304,并且不会返回资源内容,并且不会返回Last-Modify。

Last-Modified、If-Modified-Since一般来说都是非常可靠的,但有可能出现的问题是:服务器上的资源变化了,但是最后的修改时间却没有变化。这一对header就无法解决这种情况。于是,ETag/If-None-Match就诞生了。

ETag/If-None-Match

  1. ETag是一个资源校验码,它可以保证每一个资源是唯一的,资源变化都会导致ETag变化,跟最后修改时间无关,所以也就很好地补充了Last-Modified的不足。
  2. 浏览器第一次请求一个资源,服务器在返回这个资源的同时,会加上ETag这个 response header,这个header是服务器根据当前请求的资源生成的唯一标识。
  3. 浏览器再次请求这个资源时,会加上If-None-Match这个 request header,这个header的值就是上一次返回的ETag的值。
  4. 服务器第二次请求时,会对比浏览器传过来的If-None-Match和服务器重新生成的一个新的ETag,判断资源是否有变化。如果没有变化则返回304 Not Modified,但不返回资源内容(此时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag并无变化)。如果有变化,就正常返回资源内容(继续重复整个流程)。
  5. 浏览器如果收到304的响应,就会从缓存中加载资源。

Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。 强缓存与协商缓存的区别可以用下表来表示:

缓存类型获取资源形式状态码发送请求到服务器
强缓存从缓存取200(from cache)否,直接从缓存取
协商缓存从缓存取304(Not Modified)否,通过服务器来告知缓存是否可用

用户行为对缓存的影响

用户操作Expires/Cache-ControlLast-Modied/Etag
地址栏回车有效有效
页面链接跳转有效有效
新开窗口有效有效
前进回退有效有效
F5刷新无效有效
Ctrl+F5强制刷新无效无效

如何控制缓存

一种方法是在所有静态资源文件后面添加随机时间戳,例如

<script type="text/javascript" src="https://www.demo.com/demo.js?v=1234"></script>

每次修改demo.js之后修改v后面的时间戳,这样浏览器就会忽略缓存从服务器请求新的文件。

但是,由于html页面没有加时间戳,它页面依然是使用的缓存,html又是所有静态资源的载体,所以其他资源也是依然使用的缓存。

还有一种方法是在meta标签上添加cache-control,如下:

<!--设置过期时间设置0为直接过期并清除缓存-->
<meta http-equiv="Expires" content="0">
<!--设置不缓存页面-->
<meta http-equiv="Pragma" content="no-cache">
<!--设置不修改消息存储-->
<meta http-equiv="Cache-control" content="no-cache">
<!--同上-->
<meta http-equiv="Cache" content="no-cache">

但是,这样做并没有什么用,完全没办法避免浏览器的缓存,添加cache-control没错,但是需要在响应头添加,所以我们需要修改服务器配置。以下是nginx配置的参考:

#   利用正则表达式匹配静态资源目录
location ~ /dest/(.*) {
    root   E:/Workspace/my;
    add_header Cache-Control no-cache;
    add_header Cache-Control private;
    expires 0s;
}

如此配置后,dest目录下的所有文件将不再缓存,每次都从服务器端请求了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值