【Node.js】缓存

http 缓存分为强缓存和协商缓存。他们用于优化网站性能并减少服务器负载。这两种缓存都通过 HTTP 响应头来控制,它们分别基于不同的缓存验证方式,可以根据资源的特性和需求来选择合适的缓存策略。

客户端

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<button id="btn">send</button>
<script>
const btn = document.querySelector('#btn')
btn.addEventListener('click', ()=> {
    fetch('http://localhost:3000/api3')
})
</script>
</body>
</html>

1. 强缓存(Strong Cache)

  • 客户端在请求资源时,会检查缓存的相关响应头(如Cache-ControlExpires),如果资源的缓存尚未过期,客户端将直接从本地缓存中获取资源,而不会发送请求到服务器。
  • 常用的强缓存响应头包括:
    • Cache-Control: max-age=<seconds>:指定资源的缓存时间,单位为秒。
    • Expires: <date>:指定资源的过期时间,是一个日期字符串。它是一个 HTTP 1.0 的头部字段,但仍然被一些客户端和服务器使用。
  • 从浏览器读取缓存分为内存缓存(memory cache,浏览器内存)和硬盘缓存(disk cache,计算机硬盘,空间大,读取效率低),而这两种缓存策略由浏览器自身分配
  • 状态码为 200
import express from 'express'
import cors from 'cors'
import fs from 'node:fs'
import crypto from 'node:crypto'

const app = express()
app.use(cors())

//静态资源缓存 html, css, js, png
// app.use(express.static('./static', {
//     maxAge: 100 * 60 * 5,
//     lastModified: true
// }))

//动态资源缓存
//Expires
app.get('/api', (req, res) => {
    // 到了过期时间之后将不再进行缓存
    res.setHeader('Expires', new Date('2024-4-6 8:57:00').toUTCString())
    res.send('Expires1111')
})
// Cache-Control
// public 任何服服务器都可以缓存包括代理服务器 cdn
// private 只能浏览器缓存 不包括代理服务器
// max-age 缓存的时间
app.get('/api2', (req, res) => {
    res.setHeader('Cache-Control', 'public, max-age=10')
    res.send('Cache-Control1111')
})

app.listen(3000, () => {
    console.log('3000端口已启用')
})
  • 当 expires 和 cache-control 同时出现,cache-control 的 max-age 优先级更高

2. 协商缓存(Conditional Cache)

  • 协商缓存是指客户端在请求资源时,需要与服务器进行通信来验证缓存的有效性。
  • 常用的协商缓存响应头包括:
    • Last-Modified:指定资源的最后修改时间。
    • ETag:指定资源的实体标签(根据内容生成一个哈希),是一个唯一标识符。
  • 当客户端发送包含If-Modified-SinceIf-None-Match的请求头时,服务器会根据这些信息来判断资源是否已经发生变化,如果未发生变化,服务器将返回304 Not Modified响应,并告知客户端使用缓存。
  • 强缓存和协商缓存同时出现,默认强缓存的优先级更高(当然也可以通过 Cache-Control 响应头进行控制),如果强缓存未命中(例如max-age过期),也会发起协商缓存的请求
  • ETag 优先级比 Last-Modified 高
  • 状态码为 304
import express from 'express'
import cors from 'cors'
import fs from 'node:fs'
import crypto from 'node:crypto'

const app = express()
app.use(cors())

//获取文件的最后修改时间
const getFileModifyTime = ()=> {
    return fs.statSync('./index.js').mtime.toISOString()
}
app.get('/api3', (req,res)=> {
    // no-cache 使用协商缓存而不是强缓存
    // no-store 不走任何缓存
    res.setHeader('Cache-Control' ,'no-cache')
    const modifyTime = getFileModifyTime();
    // 浏览器根据 Last-Modified 的值自动设置 if-modified-since 的值(与上一次 Last-Modified 的值相同)
    const ifModifiedSince = req.headers['if-modified-since']
    // 如果文件不修改则不用重新缓存
    if (ifModifiedSince === modifyTime) {
        console.log('缓存了')
        res.statusCode = 304
        res.end()
        return
    }
    console.log('没有缓存')
    res.setHeader('Last-Modified', modifyTime)
    res.send('Last-Modified111')
})

app.listen(3000, () => {
    console.log('3000端口已启用')
})
import express from 'express'
import cors from 'cors'
import fs from 'node:fs'
import crypto from 'node:crypto'

const app = express()
app.use(cors())

//获取文件内容哈希
const getFileHash = ()=> {
    return crypto.createHash('sha256').update(fs.readFileSync('index.js')).digest('hex')
}
app.get('/api3', (req,res)=> {
    // no-cache 使用协商缓存而不是强缓存
    // no-store 不走任何缓存
    res.setHeader('Cache-Control' ,'no-cache')
    const fileHash = getFileHash();
    const ifNoneMatch = req.headers['if-none-match']
    // 如果文件不修改则不用重新缓存
    if (ifNoneMatch === fileHash) {
        console.log('缓存了')
        res.statusCode = 304
        res.end()
        return
    }
    console.log('没有缓存')
    res.setHeader('ETag', fileHash)
    res.send('Etag111')
})

app.listen(3000, () => {
    console.log('3000端口已启用')
})

强缓存和协商缓存可以结合使用,以提高缓存效果。通常情况下,可以首先使用强缓存来尽可能减少对服务器的请求,如果资源已经过期或者需要重新验证,则使用协商缓存来验证缓存的有效性。这样可以在保证性能的同时,确保客户端始终能够获取到最新的资源。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>