在Next.js的getServerSideProps()中实现数据获取缓存方案咨询
解决Next.js + Firestore数据缓存问题
问题根源分析
你遇到的问题原因如下:
node-cache在Serverless环境(比如Vercel、Firebase Functions)中无法持久缓存,因为每次请求可能触发函数冷启动,缓存会被重置。getServerSideProps中设置的Cache-Control头作用于响应内容缓存,而非函数内部的查询逻辑。如果没有CDN/边缘缓存层拦截请求,服务器端仍会每次执行getServerSideProps,导致getPropertyPreviewData被反复调用。
解决方案
方案1:增量静态再生(ISR)—— 最优非实时场景方案
如果页面数据允许10分钟以上的延迟,直接改用getStaticProps并配置revalidate参数。Next.js会自动静态生成页面,之后每隔指定时间后台重新生成,同时返回缓存的旧页面,完全避免重复查询。
export const getStaticProps = async () => { const properties = await getPropertyPreviewData(); return { props: { properties }, // 每600秒(10分钟)重新生成页面 revalidate: 600 }; };
方案2:Serverless环境下的服务器端缓存(必须用getServerSideProps时)
如果依赖getServerSideProps的动态能力(比如路由参数、请求上下文),需要用外部缓存系统存储查询结果:
方法A:Redis缓存
通过Redis持久化缓存Firestore查询结果,避免重复请求:
import Redis from 'ioredis'; // 初始化Redis客户端(配置从环境变量读取) const redis = new Redis(process.env.REDIS_URL); export const getServerSideProps = async (context) => { const { res } = context; // 设置CDN缓存头 res.setHeader( 'Cache-Control', 'public, s-maxage=600, stale-while-revalidate=1200' ); const cacheKey = 'property-preview-data'; // 优先读取缓存 const cachedData = await redis.get(cacheKey); if (cachedData) { return { props: { properties: JSON.parse(cachedData) } }; } // 缓存不存在时查询Firestore const properties = await getPropertyPreviewData(); // 存入缓存,设置10分钟过期 await redis.set(cacheKey, JSON.stringify(properties), 'EX', 600); return { props: { properties } }; };
方法B:Firestore内置内存缓存
启用Firestore服务器端SDK的内存缓存,适合短时间内重复请求的场景(注意:Serverless冷启动会清空缓存):
import { initializeApp } from 'firebase/app'; import { getFirestore, initializeFirestore } from 'firebase/firestore'; const firebaseApp = initializeApp(你的Firebase配置); // 初始化Firestore并启用10MB内存缓存 const db = initializeFirestore(firebaseApp, { cacheSizeBytes: 10485760 }); // 后续getPropertyPreviewData使用这个db实例查询 async function getPropertyPreviewData() { const snapshot = await db.collection('properties').get(); return snapshot.docs.map(doc => doc.data()); }
方案3:Edge Functions缓存(适合边缘部署场景)
如果部署在支持Edge Functions的平台(如Vercel),可以将数据查询逻辑移到Edge API路由,利用边缘缓存大幅降低请求延迟:
// pages/api/properties.js export const config = { runtime: 'edge' }; export default async function handler(req) { const cacheControl = 'public, s-maxage=600, stale-while-revalidate=1200'; // 检查Edge缓存 const cachedResp = await caches.default.match(req.url); if (cachedResp) { return new Response(cachedResp.body, { headers: { ...cachedResp.headers, 'Cache-Control': cacheControl } }); } // 查询Firestore const properties = await getPropertyPreviewData(); const resp = new Response(JSON.stringify(properties), { headers: { 'Content-Type': 'application/json', 'Cache-Control': cacheControl } }); // 存入Edge缓存 await caches.default.put(req.url, resp.clone()); return resp; }
之后页面通过fetch('/api/properties')获取数据,页面本身用静态生成即可。
内容的提问来源于stack exchange,提问作者J. Whitehead
相关产品推荐
相关产品推荐

