You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 21:50:21