浏览器的缓存机制是指浏览器可以缓存数据下来,当再次发起请求时,可以在浏览器的缓存中取出,无需再从服务器请求重复加载新数据。
浏览器的缓存机制是由强缓存和协商缓存实现的,其优点是减少网络数据传输,减少服务器负担,提升客服端加载速度。
Status Code: 200 OK (from memory cache)
不会向服务器发起请求,直接从缓存中取出资源Status Code: 304 Not Modified
无需要重新加载新数据,反之重新加载新数据。强缓存根据 expires 和 cache-control 字段来控制的。
首先在 HTTP1.1 版本前,是用 expires 字段控制强缓存,返回的是一个资源过期的时间戳。当想发起服务器请求时,浏览器会根据 expires 的时间戳和本地时间戳对比
,如果未过期,则使用浏览器的缓存。
缺点:[根据 expires 的时间戳和本地时间戳对比],如果修改本地时间,那就不准确了。所以HTTP1.1 版后引入了 cache-control: max-age
字段控制。
max-age
字段返回的是一个时间秒数,它会根据 response headers 返回的响应时间 + max-age
时间内,缓存都有效。
当然 cache-control 还有几个比较常用的值:
// 处理加载图片资源 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对字段实现的:
首先、当第一次发起服务器请求数据响应成功回来时,会 Response Headers 会携带 Last-Modifiled 字段回来,该值是服务器返回该资源的修改时间。
然后、当再次发起服务器请求时,浏览器会把 Last-Modifiled 的值会设置到 Request Headers 中的 If-Last-Modifiled 值中,携带发送到服务器
最后服务器会根据 Request Headers 中的 If-Last-Modifiled 的值和 Last-Modifiled 的值对比是否相同,如果相同返回 Status Code: 304 Not Modified
,无需要重新加载新数据,反之重新加载新数据。
首先、当第一次发起服务器请求数据响应成功回来时,会 Response Headers 会携带 Etag 字段回来,该值是服务器返回的是根据该资源的最新修改内容生成唯一的Key。
然后、当再次发起服务器请求时,浏览器会把 Etag 的值会设置到 Request Headers 中的 If-None-Match 值中,携带发送到服务器
最后服务器会根据 Request Headers 中的 If-None-Match 的值和 Etag 的值对比是否相同,如果相同返回 Status Code: 304 Not Modified
,无需要重新加载新数据,反之重新加载新数据。
// 处理加载图片资源 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,可以下载项目下来改改跑一下,体验一下印象会更深刻!