为了账号安全,请及时绑定邮箱和手机立即绑定

浏览器的缓存机制-强缓存和协商缓存

强缓存和协商缓存

浏览器的缓存机制是指浏览器可以缓存数据下来,当再次发起请求时,可以在浏览器的缓存中取出,无需再从服务器请求重复加载新数据。

浏览器的缓存机制是由强缓存和协商缓存实现的,其优点是减少网络数据传输,减少服务器负担,提升客服端加载速度。

强缓存和协商缓存的区别

  • 如果命中强缓存,返回状态码 Status Code: 200 OK (from memory cache)不会向服务器发起请求,直接从缓存中取出资源
  • 如果命中协商缓存,会向服务器发起请求询问资源是否过期,如果未过期返回 Status Code: 304 Not Modified 无需要重新加载新数据,反之重新加载新数据。

图示

image

强缓存的机制

强缓存根据 expires 和 cache-control 字段来控制的。

首先在 HTTP1.1 版本前,是用 expires 字段控制强缓存,返回的是一个资源过期的时间戳。当想发起服务器请求时,浏览器会根据 expires 的时间戳和本地时间戳对比,如果未过期,则使用浏览器的缓存。

缺点:[根据 expires 的时间戳和本地时间戳对比],如果修改本地时间,那就不准确了。所以HTTP1.1 版后引入了 cache-control: max-age 字段控制。

max-age 字段返回的是一个时间秒数,它会根据 response headers 返回的响应时间 + max-age 时间内,缓存都有效。

当然 cache-control 还有几个比较常用的值:

  • public 可以被浏览器和代理服务器缓存
  • private 只能被浏览器缓存(默认)
  • s-maxage 和 max-age 同理,s-maxage 是代理服务器的有效期,s-maxage和max-age同时存在的换,s-maxage 优先
  • no-store 当设置了这个值,浏览器会忽视所有缓存,每次都会向服务器发起新的请求,取最新的数据
  • no-cache 当设置了这个值,就是协商缓存的机制,浏览器都会先发起向服务器询问请求,询问判断缓存的资源是否可用,如果服务器判断资源可用则返回 304 状态码,缓存数据可以继续使用,从浏览器取出数据即可;反之返回200状态,且最新数据。

Koa2 示例代码 - 强缓存

// 处理加载图片资源
router.get(/\S*\.(jpe?g|png)$/, async (ctx, next) => {
    const { path } = ctx;
    ctx.type = mime.getType(path)

    const imagePath = Path.resolve(__dirname, `.${path}`)
    const imageBuffer = await fs.readFile(imagePath)

    // 同时存在,max-age 优先
    // max-age 设置 120s 内有效
    ctx.set('cache-control', 'max-age=120')
    // expires 设置 60s 内有效
    ctx.set('expires', new Date(Date.now() + 1 * 60 * 1000).toUTCString())

    ctx.body = imageBuffer

    await next()
})

协商缓存的机制

协商缓存的机制实现是根据2对字段实现的:

  • Last-Modifiled / If-Last-Modifiled 根据文件的修改时间判断资源是否过期
  • Etag / If-Node-Match 根据文件的修改内容生成唯一Key判断资源是否过期,与 Last-Modifiled 同时存在时,Etag 优先

Last-Modifiled / If-Last-Modifiled

首先、当第一次发起服务器请求数据响应成功回来时,会 Response Headers 会携带 Last-Modifiled 字段回来,该值是服务器返回该资源的修改时间。

然后、当再次发起服务器请求时,浏览器会把 Last-Modifiled 的值会设置到 Request Headers 中的 If-Last-Modifiled 值中,携带发送到服务器

最后服务器会根据 Request Headers 中的 If-Last-Modifiled 的值和 Last-Modifiled 的值对比是否相同,如果相同返回 Status Code: 304 Not Modified,无需要重新加载新数据,反之重新加载新数据。

ETag / If-Node-Match

首先、当第一次发起服务器请求数据响应成功回来时,会 Response Headers 会携带 Etag 字段回来,该值是服务器返回的是根据该资源的最新修改内容生成唯一的Key。

然后、当再次发起服务器请求时,浏览器会把 Etag 的值会设置到 Request Headers 中的 If-None-Match 值中,携带发送到服务器

最后服务器会根据 Request Headers 中的 If-None-Match 的值和 Etag 的值对比是否相同,如果相同返回 Status Code: 304 Not Modified,无需要重新加载新数据,反之重新加载新数据。

Koa2 示例代码 - 协商缓存

// 处理加载图片资源
router.get(/\S*\.(jpe?g|png)$/, async (ctx, next) => {
    const { path } = ctx
    ctx.type = mime.getType(path)

    const imagePath = Path.resolve(__dirname, `.${path}`)
    const imageStatus = await fs.stat(imagePath)
    const lastModified = imageStatus.mtime.toGMTString()
    const ifModifiedSince = ctx.request.headers['if-modified-since']

    // 如果命中,返回状态304
    if(ifModifiedSince === lastModified) {
        ctx.status = 304
    } else {
        const imageBuffer = await fs.readFile(imagePath)
        ctx.set('cache-control', 'no-cache')
        ctx.set('last-modified', lastModified)
        ctx.body = imageBuffer
    }

    await next()
})

详细代码仓库:https://github.com/lfb/http-cache,可以下载项目下来改改跑一下,体验一下印象会更深刻!

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
4320
获赞与收藏
1744

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消