通过 koa2 服务器实践探究浏览器HTTP缓存机制

本文通过Koa2服务器探讨浏览器HTTP缓存机制,包括强缓存和协商缓存的实现、相关头部字段及其优先级。通过示例服务器,详细解析了强缓存的expires和cache-control字段,以及协商缓存的if-modified-since、last-modified和if-none-match、etag字段。最后讨论了如何更新配置了强缓存的资源。
摘要由CSDN通过智能技术生成

浏览器 HTTP 缓存是一种常见的 web 性能优化的手段,也是在前端面试中经常被考察的一个知识点。本文通过配置 koa2 服务器,在实践中带你探究浏览器的 HTTP 缓存机制。

先来直观认识一下浏览器 HTTP 缓存:

上面是打开浏览器后直接访问 V2EX 首页后的截图,矩形圈起来的那块也就是 size 部分显示的都是 from disk cached,说明这些资源命中了强缓存,强缓存的状态码都是 200。

再来看看我直接访问上面箭头指向的那张图片是什么情况:

可以看到返回码是 304,并且请求的时候带上了协商缓存用于协商的两个请求头 if-modified-since 和 if-none-match,命中了协商缓存。可能有部份读者看到这里不太理解我前面提到的强缓存和协商缓存是什么鬼,没关系,看到最后再回过头来看,你就自然能清晰的看懂我上面圈起来的东西和提到的一些不懂术语。

缓存判断规则是怎么实现的

其实所有的网络协议都是一套规范,客户端和服务器端是怎么只是按照规范来实现而已。浏览器 HTTP 缓存也是如此,浏览器在开发的时候便按照 HTTP 缓存规范来开发,我们开发的 HTTP 服务器也应该遵守其规范。当然了,服务器是你自己写的,你完全可以不按规范来,但是浏览器不知道你在搞什么名堂啊,HTTP 缓存肯定不会正常工作了。

我们知道浏览器和服务器进行交互的时候会发送一些请求数据和响应数据,我们称之为HTTP报文。

与缓存相关的规则信息就包含在报文首部中。下面是 chrome network 面板中的信息:

浏览器的 HTTP 缓存协议本质上就通过请求响应过程中在首部中携带那些和缓存相关的字段来实现的。

浏览器 HTTP 缓存的分类

浏览器 HTTP 缓存分两钟:

  1. 强缓存
  2. 协商缓存

强缓存指的是浏览器在本地判定缓存有无过期,未过期直接从内存或磁盘读取缓存,整个过程不需要和服务器通信。

协商缓存需要向服务器发送一次协商请求,请求时带上和协商缓存相关的请求头,由服务器判断缓存是否过期,未过期就返回状态码 304,浏览器当发现响应的返回码是 304,也直接是读取本地缓存,如果服务器判定过期就直接返回请求资源和 last-modified,状态码为 200。

浏览器请求资源时判定缓存的简略流程如下图:

文字解释一下:当浏览器请求一个资源时,浏览器会先从内存中或者磁盘中查看是否有该资源的缓存。如果没有缓存,可能浏览器之前没访问过这个资源或者缓存被清除了那只能向服务器请求该资源。

如果有缓存,那么就先判断有没有命中强缓存。如果命中了强缓存则直接使用本地缓存。如果没有命中强缓存但是上次请求该资源时返回了和协商缓存相关的响应头如 last-modified 那么就带上和协商缓存相关的请求头发送请求给服务器,根据服务器返回的状态码来判定是否命中了协商缓存,命中了的话是用本地缓存,没有命中则使用请求返回的内容。

强缓存和协商缓存的区别
  1. 命中时状态码不同。强缓存返回 200,协商缓存返回 304。
  2. 优先级不同。先判定强缓存,强缓存判断失败再判定协商缓存。
  3. 强缓存的收益高于协商缓存,因为协商缓存相对于强缓存多了一次协商请求。

演示服务器说明

整个 koa2 演示服务器在这:koa2-browser-HTTP-cache。总共就几个文件,index.js 入口文件,index.html 首页源代码,sunset.jpg 和 style.css 是 index.html 用到的图片和样式。

服务器代码代码很简单,使用 koa-router 配了三个路由,目前还没有写缓存相关的代码。

// src/index.js
const Koa = require('koa');
const Router = require('koa-router');
const mime = require('mime');
const fs = require('fs-extra');
const Path = require('path');

const app = new Koa();
const router = new Router();

// 处理首页
router.get(/(^\/index(.html)?$)|(^\/$)/, async (ctx, next) => {
    ctx.type = mime.getType('.html');

    const content = await fs.readFile(Path.resolve(__dirname, './index.html'), 'UTF-8');
    ctx.body = content;

    await next();
});

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

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

    await next();
});

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值