next.js中实现缓存

🧩 一、缓存的核心思路 在 Fastify + Next.js 场景下,缓存通常分为三层:

缓存层级 缓存内容 适用场景
1. HTTP Header 缓存(浏览器/CDN 层) 静态资源、HTML 页面 CDN 前置缓存、浏览器缓存控制
2. 内存缓存(进程内) 接口数据、配置、语言包、皮肤数据 小规模、高并发场景下的快速命中
3. 外部缓存(Redis 等) 登录态、用户信息、接口响应 分布式服务场景,多节点共享

⚙️ 二、典型应用场景

✅ 常见你在自定义 Fastify 服务器中会缓存的内容包括:

  • /fePublicInfo 这样的公共接口(语言包、皮肤配置)
  • 登录用户的简要信息(token→user)
  • SSR 数据预加载(例如首页接口)
  • 远程配置文件、CDN JSON 等

🧠 三、Fastify 缓存的常用实现方式

方式一 :使用内存缓存(最简单) 使用 Maplru-cache 作为本地缓存。

✅ 示例:缓存 /fePublicInfo 响应 10 分钟

kotlin 复制代码
import Fastify from 'fastify'
import LRU from 'lru-cache'

const fastify = Fastify()
const cache = new LRU({
  max: 100,           // 最多缓存 100 条
  ttl: 1000 * 60 * 10 // 缓存 10 分钟
})

fastify.get('/api/fePublicInfo', async (req, reply) => {
  const cacheKey = 'fePublicInfo'
  const cached = cache.get(cacheKey)

  if (cached) {
    // 命中缓存
    reply.header('x-cache', 'HIT')
    return cached
  }

  // 缓存未命中 → 请求远程服务
  const res = await fetch('https://api.xxx.com/fePublicInfo')
  const data = await res.json()

  // 写入缓存
  cache.set(cacheKey, data)
  reply.header('x-cache', 'MISS')
  return data
})

fastify.listen({ port: 3000 })

🔹 优点:超简单、适合小规模服务

🔹 缺点:内存缓存无法跨进程共享,适合单实例部署

方式二:使用 Redis 缓存(推荐生产环境) ✅ 示例:基于 Redis 缓存 API 响应

javascript 复制代码
import Fastify from 'fastify'
import Redis from '@fastify/redis'

const fastify = Fastify()

fastify.register(Redis, { host: '127.0.0.1', port: 6379 })

fastify.get('/api/fePublicInfo', async (req, reply) => {
  const cacheKey = 'fePublicInfo'
  const cached = await fastify.redis.get(cacheKey)

  if (cached) {
    reply.header('x-cache', 'HIT')
    return JSON.parse(cached)
  }

  const res = await fetch('https://api.xxx.com/fePublicInfo')
  const data = await res.json()

  // 缓存 10 分钟
  await fastify.redis.set(cacheKey, JSON.stringify(data), 'EX', 60 * 10)
  reply.header('x-cache', 'MISS')
  return data
})

🔹 优点:跨实例共享、持久化、可限流

🔹 缺点:多一次网络开销

方式三:对 SSR 页面做缓存(全页缓存) 适用于不经常变化的 SSR 页面,比如首页或营销页。

✅ 示例:缓存 SSR 渲染结果

javascript 复制代码
import Fastify from 'fastify'
import LRU from 'lru-cache'
import next from 'next'

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

const fastify = Fastify()
const pageCache = new LRU({ max: 100, ttl: 1000 * 60 * 5 }) // 5分钟缓存

fastify.get('/', async (req, reply) => {
  const cacheKey = 'page:/'

  if (pageCache.has(cacheKey)) {
    reply.header('x-cache', 'HIT').type('text/html')
    return reply.send(pageCache.get(cacheKey))
  }

  const html = await app.renderToHTML(req.raw, reply.raw, '/', req.query)
  pageCache.set(cacheKey, html)

  reply.header('x-cache', 'MISS').type('text/html')
  reply.send(html)
})

fastify.all('*', (req, reply) => handle(req.raw, reply.raw))

🔹 优点:显著提升 SSR 页面性能

🔹 缺点:要注意缓存失效逻辑(如语言切换、登录态)

方式四:利用 HTTP 缓存头(CDN + 浏览器)

rust 复制代码
reply.header('Cache-Control', 'public, max-age=300, stale-while-revalidate=60')

这告诉 CDN/浏览器:

  • 正常缓存 300 秒;
  • 超时后可继续用旧缓存 60 秒,同时异步更新。

综合最佳实践 在中大型项目中,推荐组合策略:

层级 缓存内容 技术
CDN 层 图片、静态资源 Cache-Control
Fastify 层 公共接口 Redis / LRU
SSR 层 页面 HTML LRU / Redis
客户端层 用户操作数据 localStorage / SW
  • 静态资源通过 CDN + Cache-Control 头;

  • 接口数据通过 Fastify 插件(LRU 或 Redis)缓存;

  • SSR 页面通过 LRU 做全页缓存;

  • 并结合 stale-while-revalidate 策略提升实时性。

    这样既保证了性能,也避免缓存击穿问题。

相关推荐
xixixin_2 小时前
【React】为什么移除事件要写在useEffect的return里面?
前端·javascript·react.js
嘗_2 小时前
react 源码2
前端·javascript·react.js
我只会写Bug啊6 小时前
Vue文件预览终极方案:PNG/EXCEL/PDF/DOCX/OFD等10+格式一键渲染,开源即用!
前端·vue.js·pdf·excel·预览
扯蛋4387 小时前
LangChain的学习之路( 一 )
前端·langchain·mcp
Mr.Jessy8 小时前
Web APIs学习第一天:获取 DOM 对象
开发语言·前端·javascript·学习·html
ConardLi9 小时前
Easy Dataset 已经突破 11.5K Star,这次又带来多项功能更新!
前端·javascript·后端
冴羽9 小时前
10 个被严重低估的 JS 特性,直接少写 500 行代码
前端·javascript·性能优化
rising start9 小时前
四、CSS选择器(续)和三大特性
前端·css
一 乐9 小时前
高校后勤报修系统|物业管理|基于SprinBoot+vue的高校后勤报修系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·毕设
爱喝水的小周9 小时前
《UniApp 页面配置文件pages.json》
前端·uni-app·json