前端大杂烩http

HTTP 缓存

2022-08-04  本文已影响0人  lio_zero

强缓存

HTTP/1.0 使用的是 Expires 字段,HTTP/1.1 使用的是 Cache-Control 字段。

以下是使用 Node 模拟的简单示例

const http = require('http')
const fs = require('fs')

const server = http.createServer((req, res) => {
  const time = new Date()
  time.setTime(time.getTime() + 100 * 1000) // 时间戳计算后 10s
  const expires = time.toUTCString() // GMT(格林尼治标准时间)时间格式
  res.setHeader('Expires', expires)

  // 优先级高于 Expires
  res.setHeader('Cache-Control', 'max-age=30')
  const html = fs.readFileSync('./src/index.html', 'utf8')
  res.end(html)
})

server.listen(3000)

ExpiresCache-Control 同时存在时,优先考虑 Cache-Control 字段。当缓存资源失效了,也就是没有命中强缓存,接下来就进入协商缓存。

协商缓存

如果缓存过期了,我们就可以使用协商缓存来解决问题。协商缓存需要请求,如果缓存有效会返回 304。协商缓存需要客户端和服务端共同实现,和强缓存⼀样,也有两种实现方式 Last-ModifiedETag

Last-Modified

Last-Modified 表示本地文件最后修改时间,If-Modified-Since 会将 Last-Modified 的值发送给服务器,询问服务器在该时间后资源是否有更新,有更新的话就会将新的资源发送回来。

以下是使用 Node 模拟的简单示例

const http = require('http')
const fs = require('fs')

const server = http.createServer((req, res) => {
  const reqModified = req.headers['if-modified-since']
  const info = fs.statSync('./src/index.html')
  const lastModified = info.mtime.toUTCString() // GTM

  if (reqModified && reqModified === lastModified) {
    console.log('浏览器走缓存')
    res.statusCode = 304
    res.end()
    return
  }

  res.setHeader('Last-Modified', lastModified)
  const html = fs.readFileSync('./src/index.html', 'utf8')
  res.end(html)
})

server.listen(3000)

但是如果在本地打开缓存文件,就会造成 Last-Modified 被修改,所以在 HTTP/1.1 出现了 ETag

ETag

ETag 类似于文件指纹,If-None-Match 会将当前 ETag 发送给服务器,询问该资源 ETag 是否变动,有变动的话就将新的资源发送回来。并且 ETag 优先级⽐ Last-Modified 高。

const http = require('http')
const fs = require('fs')
const crypto = require('crypto')

const server = http.createServer((req, res) => {
  const buffer = fs.readFileSync('./src/index.html') // 二进制文件流
  const hashTool = crypto.createHash('md5') // 使用 md5 加密算法
  hashTool.update(buffer, 'utf8') // 注入二进制
  const md5 = hashTool.digest('hex') // 生成 md5 加密的唯一标识 hash
  const reqETag = req.headers['if-none-match']
  if (reqETag && reqETag === md5) {
    console.log('ETag 缓存')
    res.statusCode = 304
    res.end()
    return
  }

  const reqModified = req.headers['if-modified-since']
  const info = fs.statSync('./src/index.html')
  const lastModified = info.mtime.toUTCString() // GTM

  if (reqModified && reqModified === lastModified) {
    console.log('modified 缓存')
    res.statusCode = 304
    res.end()
    return
  }

  res.setHeader('Last-Modified', lastModified)
  res.setHeader('ETag', md5)
  const html = fs.readFileSync('./src/index.html', 'utf8')
  res.end(html)
})

server.listen(3000)

注意:以上使用 Node 进行模拟的示例,真实情况具体如何要看服务器那边如何配置。

Last-ModifiedETag 的对比

如果两者都存在,优先判断 If-None-Match 进行 ETag 协商缓存。

缓存位置

当命中强缓存和协商缓存返回 304 时,浏览器会从缓存中获取资源。

浏览器中的缓存位置一共有四种,按优先级从高到低排列分别是:

浏览器在选择 Disk Cache 与 Memory Cache 的存储上:内容使用率高的,文件优先进入磁盘。比较大的 JS、CSS 文件会直接放入磁盘,反之放入内存。

强缓存与协商缓存区别

总结

首先检查 Cache-Control,验证强缓存是否可用


本文首发 blog,如果喜欢或者有所启发,欢迎 Star,对作者也是一种鼓励。

上一篇 下一篇

猜你喜欢

热点阅读