将 HTML 在服务器端生成后返回浏览器,解决 SPA 首屏加载慢、SEO 不友好的核心痛点。

核心概念 Link to heading

SSR(Server-Side Rendering) 指的是在服务器端完成页面渲染,将完整的 HTML 返回给浏览器,而非传统的客户端 JavaScript 动态生成 DOM。

对比两种渲染方式:

渲染方式HTML 来源首屏速度SEO
CSR(客户端渲染)空 HTML + JS 构建慢,需下载执行 JS搜索引擎抓取困难
SSR(服务端渲染)服务器返回完整 HTML快,直接渲染友好

SSR 的渲染流程:

flowchart LR A[浏览器请求] --> B[服务器接收] B --> C[执行组件渲染] C --> D[生成完整 HTML] D --> E[返回浏览器] E --> F[浏览器直接显示页面]

为什么需要 SSR Link to heading

客户端渲染(React/Vue SPA)有三个本质问题:

1. 首屏白屏时间长

浏览器需要经历:下载 HTML → 下载 JS bundle → 解析执行 JS → 请求 API → 渲染 DOM。任何一个环节慢都会延长白屏。

2. SEO 不友好

虽然 Google 能执行 JS 抓取,但百度等搜索引擎对 JS 渲染的支持有限。SPA 页面在爬虫眼中通常是空内容。

3. 低端设备性能差

大量 JS 在低端手机上解析执行缓慢,用户交互体验差。

安装配置 Link to heading

Next.js(React 生态最流行的 SSR 框架)为例:

npx create-next-app@latest my-app --typescript
cd my-app
npm run dev

Next.js 默认所有路由使用 SSR(或静态生成),无需额外配置。

实际使用 Link to heading

场景一:服务端获取数据 Link to heading

在 Next.js App Router 中,Server Component 默认在服务端运行:

// app/products/page.tsx
async function getProducts() {
  const res = await fetch("https://api.example.com/products", {
    next: { revalidate: 60 }, // ISR: 60秒缓存
  });
  return res.json();
}

export default async function ProductsPage() {
  const products = await getProducts();

  return (
    <main>
      <h1>商品列表</h1>
      <ul>
        {products.map((p) => (
          <li key={p.id}>
            {p.name} - ¥{p.price}
          </li>
        ))}
      </ul>
    </main>
  );
}

服务端组件的优势:

  • 不会打包到客户端 bundle,减小 JS 体积
  • 可直接访问数据库或内部 API,无需暴露密钥
  • 支持流式渲染(Suspense),优先展示首屏内容

场景二:客户端交互 + 服务端渲染混合 Link to heading

需要交互的组件标记为 'use client',其余保持服务端渲染:

// app/cart/page.tsx — 服务端组件
import { CartList } from "./cart-list"; // 服务端
import { CartSummary } from "./summary"; // 客户端交互

export default async function CartPage() {
  const cart = await fetchCartFromDB();

  return (
    <>
      <CartList items={cart.items} /> {/* SSR,服务端渲染 */}
      <CartSummary items={cart.items} /> {/* 客户端 hydrate */}
    </>
  );
}
flowchart TB subgraph 服务端 A[Server Component] --> B[直接查数据库] B --> C[生成 HTML] end subgraph 客户端 C --> D[浏览器渲染 HTML] D --> E[Client Component hydrate] E --> F[用户交互] end

场景三:Vue 3 + Nuxt Link to heading

Vue 生态的 SSR 方案以 Nuxt 为代表,使用方式类似:

<!-- pages/products.vue -->
<script setup>
const { data: products } = await useFetch("/api/products");
</script>

<template>
  <div>
    <h1>商品列表</h1>
    <div
      v-for="p in products"
      :key="p.id"
    >
      {{ p.name }} - ¥{{ p.price }}
    </div>
  </div>
</template>

Nuxt 的 useFetch 在服务端自动执行数据获取,HTML 返回后再在客户端 hydrate。

权衡 Link to heading

SSR 并非银弹,需要接受以下代价:

代价说明
服务器负载增加每次请求都需要服务端渲染,CPU 开销大于静态托管
响应延迟受服务端影响服务端渲染慢会直接拖慢 TTFB
Node.js 依赖需要维护 Node.js 运行环境,部署复杂度上升
部分库不兼容 SSR依赖 window / document 的库需做兼容处理

何时不该用 SSR:纯后台管理面板、对 SEO 无要求的内部工具、更新频繁但访问量低的数据看板——这些场景用 CSR 更简单。

官方链接 Link to heading

[1] https://nextjs.org/docs/app/building-your-application/rendering/server-components

[2] https://nuxt.com/docs/guide/concepts/rendering

[3] https://react.dev/reference/rsc/server-components

Signature Link to heading

本文由 AI 生成,不保证正确,仅作参考