NextJS 之 ISR缓存优化

Date
Created
Oct 16, 2025 09:38 AM
Descrption
不断优化
Tags
Next.js
架构设计
工程优化
notion image
私以为SSR已经算极大的可以加速页面打开速度,但是其实理解的太片面了,SSR顶多是每次在服务端提前把脱水页面绘制好,通过网络请求交给前端,前端再进行一个展示;流程上虽然比CSR方便很多,但是其实每次还是有服务端的渲染流程,因此对服务端性能消耗比较高;所以由此延伸出了ISR;

先来看SSR和ISR的对比:

  • SSR (Server-Side Rendering): 传统的服务器端渲染。每次页面请求都在服务器上完成渲染,然后返回完整的 HTML。
  • ISR (Incremental Static Regeneration): 增量静态再生。它是 SSR 和 SSG 的混合体,提前生成静态页面,但允许在后台按需或按间隔增量地重新渲染和更新这些页面。
下面我们通过一个详细的对比表格和讲解来剖析它们的异同与优势。

核心异同对比表

特性
SSR (Server-Side Rendering)
ISR (Incremental Static Regeneration)
工作原理
用户请求时,服务器实时渲染页面,返回 HTML。
预先生成静态页面,并可在后台增量更新特定页面。
性能表现
首屏加载快,但 TTFB 可能较慢(因服务器需实时计算)。
极致性能(直接提供静态文件),TTFB 极低,类似 CDN。
可扩展性
相对较差。每个动态请求都消耗服务器资源,需要更强大的服务器或集群。
极佳。大部分请求由 CDN 响应,服务器压力极小,成本低。
数据实时性
。每次请求都使用最新数据渲染,适合数据变化频繁的场景。
可控的延迟。可以设定重新验证时间,在“速度”和“新鲜度”间取得平衡。
SEO 支持
完美支持。爬虫每次都能收到完全渲染的内容。
完美支持。爬虫收到的是静态 HTML,内容始终可用。
典型使用场景
高度动态、用户个性化的页面(如 Dashboard、社交网络动态)。
数据更新不极度频繁的大规模网站(如新闻站、电商产品页、博客)。
构建时影响
无构建时渲染,所有工作在运行时完成。
首次构建时生成页面,后续可触发增量再生。
技术代表
Next.js (Node.js), Nuxt.js (Vue), 传统后端框架 (PHP, Ruby)
Next.js (V9.5+ 独家特性),是 SSG 的强大演进。

深入解析与优势分析

SSR 的优势与特点

  1. 始终如一的实时数据: 这是 SSR 最大的优势。对于每个用户请求,页面都会用最新的数据重新渲染。这对于股票行情、实时体育比分、个人用户数据等场景是必须的。
  1. 简单的数据获取: 在 Next.js 等框架中,使用 getServerSideProps 函数,可以很自然地在服务器端获取页面所需的所有数据。
  1. 首屏性能与 SEO: 解决了 CSR 应用首屏加载白屏和 SEO 不友好的问题。
SSR 的劣势:
  • 服务器开销大: 每个请求都需要服务器进行渲染,CPU 和内存消耗高,尤其是在流量高峰时期。
  • TTFB 可能较慢: 因为要等待数据获取和渲染,首字节时间可能比直接返回静态文件要长。
  • 缓存更复杂: 虽然可以对页面进行缓存,但对于个性化内容,缓存策略会变得复杂。

ISR 的优势与特点 (Next.js 范例)

ISR 可以看作是 “带缓存的 SSR”“可更新的 SSG”。它的核心优势在于平衡了性能、规模和内容新鲜度。
  1. 极致的性能与扩展性:
      • 页面作为静态文件提供,拥有和 SSG 一样的极快加载速度和极低的 TTFB。
      • 通过全球 CDN 分发,可以轻松应对海量流量,服务器成本极低。
  1. 增量更新 - 核心创新点:
      • 背景再生: 当访问一个过期的页面(超过了设定的 revalidate 时间)时,ISR 会立即返回旧的、已缓存的页面,同时在后台触发一次新的渲染。下次访问时,将得到新的页面。
      • 按需再生: Next.js 还支持 getStaticProps 配合 revalidate,以及更高级的 On-Demand Revalidation,允许你通过 API 路由手动触发特定页面的再生(例如,当 CMS 内容更新时)。
  1. 永不丢失的页面:
      • 即使后台再生失败,网站依然可以继续服务于旧的、可用的静态页面,保证了网站的可用性。
ISR 的劣势:
  • 数据非绝对实时: 存在一个“时间窗口”,用户可能看到的是稍旧的数据(直到下一次再生完成)。不适合要求绝对实时的场景。
  • 复杂性: 缓存失效和按需再生的逻辑需要精心设计。
  • 平台锁定: 目前 ISR 主要是 Next.js 的招牌特性,虽然概念可以被其他平台借鉴,但原生支持最好的是 Vercel 平台。
 

那么在NextJS里如何做ISR:

💡
首先你得辨别一下,什么页面适合做ISR,一般首屏展示速度要求很高的页面,并且变化频率比较低的页面适合,比如说网站的Landing Page;
给一个例子:
src/app/page.tsx
import { TryIt } from '@/components/TryIt' import { NavBar } from '@/components/NavBar' import { CopyRightFooter } from '@/components/CopyRightFooter' import { HeroSection } from '@/components/HeroSection' import { WorksGuide } from '@/components/WorksGuide' import { FeatureSection } from '@/components/FeatureSection' import { TheresAnAiForThat } from '@/components/TheresAnAiForThat' import { EndorsementSection } from '@/components/EndorsementSection' import { TestimonialsSection } from '@/components/TestimonialsSection' // 静态生成配置 export const revalidate = 3600 // 1小时重新验证一次 export const dynamic = 'force-static' // 强制静态生成 export default function Home() { return ( <div className="min-h-screen bg-gradient-to-b from-background to-muted/30"> <NavBar /> {/* Hero Section */} <HeroSection /> {/* Theres An AI For That */} <TheresAnAiForThat /> {/* Works Guide */} <WorksGuide /> {/* Endorsement Section */} <EndorsementSection /> {/* Testimonials Section */} <TestimonialsSection /> {/* Feature Section */} <FeatureSection /> {/* CTA Footer */} <TryIt /> {/* Footer */} <CopyRightFooter /> </div> ) }
可以看到,这个页面不是客户端组件,同时还配置了静态生成配置1个小时,那么意味着一个小时内的用户访问都是直接把这个页面交给用户,服务端只需要渲染好一次,后续访问都不需要再次渲染,相比起SSR,每次服务端渲染好,交给客户端相比就又节省了时间。
同时还应该加一个配置到next.config.ts:
const nextConfig: NextConfig = withAxiom({ output: 'standalone', assetPrefix: '/synth-speak', reactStrictMode: false, // 添加缓存头配置(仅浏览器缓存,无CDN) async headers() { return [ { source: '/', headers: [ { key: 'Cache-Control', value: 'public, max-age=3600, stale-while-revalidate=86400', }, // 添加ETag支持,部署时自动失效 { key: 'ETag', value: `"${process.env.BUILD_ID || Date.now()}"`, }, ], }, ] },