内容站选静态还是 SSR:怎么判断(2026)

静态和 SSR 在 Next.js 或 Astro 项目里看着差不多,直到你扩容、上线、看账单。本文用 2026 年真实价格和配置讲清内容站怎么选。

静态还是 SSR,这一个决定悄悄定下了你的托管账单、首字节时间、Core Web Vitals,以及半夜被 500 报警叫醒的频率。内容站的答案几乎总是”以静态为主,只在真正需要的地方撒点动态”。本文教你怎么真的做判断,看看当前 Next.js 和 Astro 里配置长什么样,以及 2026 年 6 月各条路分别要花多少钱。

一句话结论

  • 默认静态:凡是对所有匿名访客都返回同一份 HTML 的页面(文章、文档、营销页),一律静态。
  • ISR(每 N 秒重新生成)是”基本静态、偶尔刷新”的中间档。多数人想用 SSR 时,其实想要的就是它。
  • SSR 只用在响应真的依赖请求的地方:登录态、地区、A/B 分组,或者每次渲染都必须最新的实时数据。
  • 静态资源在 Cloudflare、Firebase Hosting、GitHub Pages、S3 上都是免费且不计量的。一旦上了 SSR,就把 Node/Worker 运行时塞进了请求链路,原本免费的页面就变成了按次计费的函数调用。

三种模式横向对比

模式渲染时机从哪里发新鲜度成本形态
静态(SSG)构建时CDN 边缘,无服务器到下次构建为止最便宜,出口流量通常免费
ISR构建时生成,到点后重渲CDN 边缘 + 偶尔构建最多滞后 revalidate主要是 CDN + 少量函数调用
SSR每次请求Node/Worker 函数始终最新按请求付费,有冷启动

对内容站来说,90% 以上的路由都属于第一行。

每种模式在代码里长什么样

Next.js 15(App Router)

在 Next.js 15 里,路由 segment 默认不再缓存——默认的 dynamic = 'auto' 是能静态就静态、必须动态才动态。文章页通常你想去掉这种”猜”,直接强制静态:

// app/articles/[slug]/page.tsx
export const dynamic = 'force-static';
export const revalidate = false;

export async function generateStaticParams() {
  return getAllSlugs().map((slug) => ({ slug }));
}

export default async function Article({ params }: { params: { slug: string } }) {
  const post = await getPost(params.slug);
  return <Markdown source={post.body} />;
}

ISR 结构一样,只是内容按周期刷新而不用重新部署。页面里所有 fetch 中最小的那个 revalidate 决定整页:

export const revalidate = 300;  // 最多每 5 分钟重渲一次

SSR——只在页面真的依赖请求时才用。调用 cookies()headers() 会自动把这个 segment 转成动态,所以你确实要动态时就显式写出来:

export const dynamic = 'force-dynamic';  // 每次请求都打到函数

Next.js 15 里服务端 fetch() 不再像 14 那样默认隐式缓存了,所以要写明确:要缓存就传 { cache: 'force-cache' },要定时重验就传 { next: { revalidate: N } }。留着隐式不写,正是路由悄悄变动态的根源。

Astro 5

Astro 默认就是静态。注意 Astro 5 的一个变化:旧的 output: 'hybrid' 模式被移除,合并进了 static。现在按路由 SSR 不再靠改配置开关——你只要加一个 adapter,需要按需渲染的路由导出 prerender = false 即可:

// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({
  output: 'static',                    // 默认,输出纯 HTML
  adapter: node({ mode: 'standalone' }), // 只有某些路由需要 SSR 时才加
});
---
// src/pages/dashboard.astro —— 单独把这条路由开成 SSR
export const prerender = false;
---

如果没有任何路由需要服务器,干脆把 adapter 去掉,直接发纯静态文件。(本站就是这么跑的。)

怎么判断一条路由该用哪种

每条路由只问一句:同一分钟里,两个匿名访客之间有什么不同?

  • 什么都不变(同一篇文章、同一个文档页)——静态。
  • 因人或因地区而异(登录态 dashboard、地理优惠、购物车)——SSR。
  • 想要 CDN 便宜托管、延迟稳定——静态。
  • 每次渲染都必须最新的实时数据(价格、库存、比分)——SSR,或短窗口 ISR。
  • 部署到 Cloudflare Pages、Firebase Hosting、GitHub Pages、S3——静态。这些平台发的是文件;SSR 需要 Worker/函数,会改变成本和故障模型。

实际要花多少钱(2026 年 6 月)

到这里,选择就不再是纸上谈兵了。

托管静态SSR / 函数
Cloudflare静态资源所有套餐免费且不计量Workers/Pages Functions 免费档:每天 10 万次请求、每次 30ms CPU;超出按 Workers 付费价
Firebase HostingSpark 套餐免费,允许商用Cloud Functions 需要 Blaze 按量付费套餐
VercelHobby 免费但仅限非商用;100 GB 流量、4 小时 active CPUHobby 每月 100 万次函数调用;Pro 每席 $20、1 TB 流量,超出 $0.15/GB
GitHub Pages / S3静态免费 / 近乎免费无服务器运行时,做不了 SSR

有两点最容易踩坑:Vercel 的免费 Hobby 套餐仅限非商用,所以挂广告或联盟链接的内容站,严格说要上 Pro,每席每月 $20Vercel 定价)。还有 Cloudflare 上,请求静态资源是免费且无限的,但请求一旦命中 Function(SSR),就要计入每天 10 万次的免费额度(Cloudflare Pages 定价)。不小心走了动态,那是真账单,不是假设。

为什么 Core Web Vitals 上静态更占优

Google 的”良好”门槛(取真实 CrUX 现场数据的第 75 百分位,截至 2026 年 6 月)是 LCP 低于 2.5 秒、INP 低于 200 毫秒、CLS 低于 0.1。从 CDN 边缘发预构建好的 HTML,TTFB 几乎为零,而 TTFB 正是影响 LCP 最大的杠杆。SSR 给每个未命中缓存的请求都加了一次运行时往返和冷启动抖动,恰恰把 LCP 预算花在了最不该花的地方。INP 如今是最容易不达标的指标——约 43% 的站点过不了 200ms 这条线——但那是客户端 JavaScript 的问题,跟渲染模式无关,上 SSR 并不能解决。

一步步审一遍你的路由

  1. 列出每条路由,逐条标:静态、ISR(带 revalidate 窗口)、SSR、客户端渲染。
  2. 每个标了 SSR 的,问”同一分钟两个匿名访客之间有什么变化”。没变化就该静态。
  3. 每个 ISR 选一个 revalidate 窗口。多数博客 60 秒够用;价格页可能要 300 秒;几乎没有真需要 1 秒的。
  4. Next.js 里需要确定静态的路由就写上 dynamic = 'force-static',免得 layout 里一个误用的 cookies() 把整棵子树悄悄翻成动态。
  5. 每个服务端 fetch() 都显式写 cache / next.revalidate,别依赖那个在 Next.js 14 到 15 之间变过的默认行为。
  6. 构建后读输出。Next.js 会把每条路由标成 StaticSSGDynamic;逐条审,把不该是 Dynamic 的揪出来。
  7. 对部署后的页面跑 Lighthouse。TTFB 和 LCP 干净就说明选对了。

容易踩的坑

  • 不小心变动态:共享 layout 里一个 cookies()headers(),整棵子树在 Next.js 里都变动态。
  • ISR revalidate 设太狠:日更内容配 10 秒窗口,白白烧函数调用还没好处。
  • “以防万一”选 SSR:过早灵活和过早优化是一回事——你立刻就在冷启动和账单上付了钱。
  • 需要保持 CDN 可缓存的路由忘了写 dynamic = 'force-static'
  • 在只发文件的托管上硬上 SSR(GitHub Pages、纯 S3、不带 Function 的 Cloudflare Pages),然后不明白为什么不行。
  • Astro 留着用不上的 adapter:给一个本可纯静态的站点白白塞了个服务器运行时。

这篇适合谁

独立内容站——博客、文档、垂直目录、课程站——95% 以上流量看到同一份 HTML。

什么时候 SSR 才是对的

有登录墙、个性化流、购物车,或内容跟访客绑定(auth、geo、A/B)的 App。这些是真需要 SSR 或客户端渲染的,硬逼成静态会直接坏掉。

FAQ

  • ISR 是不是就是缓存版 SSR?: 效果上是。Next.js 在 revalidate 窗口过期后的第一次请求时重建页面,然后给后续所有人发缓存 HTML,直到下次过期。你拿到的是”准实时”的内容,加上 CDN 的成本。
  • 用了 CMS 还能静态吗?: 能。build 时从 Contentful / Sanity / Notion 拉数据仍然是静态。发布时用 webhook 触发重新构建,既保新鲜又保 CDN 成本。
  • Astro 真把 hybrid 模式去掉了?: 是。从 Astro 5 起,output: 'hybrid' 没有了,合并进了 output: 'static'。加一个 adapter,给需要服务器的那几条路由写 prerender = false,其余保持静态。
  • 搜索怎么办?: 基于静态 JSON 索引的客户端搜索,几千篇文章以内的内容站都够用。除非真要做大规模服务端过滤,才上 SSR 搜索。
  • 一个项目能静态和 SSR 混用吗?: 能——这正是 Next.js App Router 和 Astro adapter 的核心。每条路由自选策略。

相关阅读

标签: #独立开发 #Next.js #建站策划 #对比 #Core Web Vitals