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

如何降低Next.js框架中SSR渲染时长 优化产品页加载性能

Next.js SSR 产品页加载耗时优化方案

现有代码问题

你的代码存在1个显性bug:catch块中直接引用了仅在try作用域内定义的result变量,请求报错时会触发未定义错误,导致SSR渲染失败。其次核心性能问题是未做缓存、全量拉取数据、每次分类切换都走全页SSR请求,数据量上来后耗时必然很高。

可落地优化方案

  • 渲染策略适配
    如果产品内容更新频率低于1分钟/次,优先用ISR(增量静态再生)替代SSR,提前静态生成高频访问的分类页、详情页,设置合理的revalidate刷新周期,用户访问时直接返回静态内容,后台异步更新数据,无需每次请求都拉接口渲染。
    列表页分类切换改为客户端路由+客户端数据请求,不要每次切换都触发全页SSR刷新,配合SWR/React Query这类请求库,自动实现数据缓存、重试、预加载,同时可加骨架屏作为加载占位,避免页面长时间空白。
    必要时开启next/link的预加载能力,用户hover分类链接时就提前预取对应页面数据,减少点击后的等待时长。
  • 接口侧优化
    列表页禁止一次性拉取1000条全量数据,新增分页/无限滚动逻辑,每次仅拉取当前可见区域的20-50条数据;接口返回时裁剪冗余字段,仅返回前端渲染需要的内容,大幅降低响应体积。
    后端接口本身也可加查询缓存,相同分类、相同筛选条件的请求直接返回缓存结果,降低数据库查询压力。
  • 多层缓存叠加
    服务端侧:给SSR页面响应头设置Cache-Control: s-maxage=60, stale-while-revalidate=120,CDN/边缘节点可缓存页面内容,重复请求直接返回缓存。也可在Next.js服务端加内存缓存(比如用node-cache),相同产品ID的请求直接读缓存,无需重复调用后端接口。
    前端侧:将用户访问过的分类、产品数据存入localStorage/sessionStorage,二次访问时先读缓存渲染,后台再异步拉取最新数据更新。

优化后代码示例

ISR版本(推荐用于产品详情页)

export async function getStaticProps(context) {
  const { id, categoryId } = context.params;
  try {
    const response = await fetch(Constants.getProducts, {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ _id: id }),
    });
    const result = await response.json();
    return {
      props: { result: result.doc[0], categoryId, status: 200 },
      revalidate: 60 // 60秒后后台自动刷新静态内容,用户无感知
    }
  } catch(e) {
    return {
      props: { result: null, categoryId, status: 404 },
      revalidate: 10 // 错误页10秒后重试生成
    }
  }
}

// 需要配合getStaticPaths指定预生成的页面,或者开fallback实现动态生成
export async function getStaticPaths() {
  return {
    paths: [], // 可传入高频访问的产品ID提前生成
    fallback: 'blocking' // 未预生成的页面首次访问时SSR生成,之后走静态缓存
  }
}

带缓存的SSR版本(必须用SSR场景)

import NodeCache from 'node-cache';
// 内存缓存,缓存有效期60秒
const productCache = new NodeCache({ stdTTL: 60 });

export async function getServerSideProps(context) {
  const { id, categoryId } = context.query;
  const cacheKey = `product_${id}`;
  let result = productCache.get(cacheKey);

  // 缓存命中直接返回
  if (result) {
    return {
      props: { result: result.doc[0], categoryId, status: 200 }
    }
  }

  try {
    const response = await fetch(Constants.getProducts, {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ _id: id }),
    });
    result = await response.json();
    // 写入缓存
    productCache.set(cacheKey, result);
    // 加HTTP缓存,CDN可直接缓存页面
    context.res.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate=120');
    return {
      props: { result: result.doc[0], categoryId, status: 200 }
    }
  } catch(e) {
    return {
      props: { result: null, categoryId, status: 404 }
    }
  }
}

内容的提问来源于stack exchange,提问作者Pooja

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 05:39:03