跳到主要内容

JavaScript SSR服务端渲染

什么是服务端渲染(SSR)?

服务端渲染(Server-Side Rendering,简称SSR)是一种网页渲染技术,它允许在服务器上生成完整的HTML页面,然后将其发送到客户端浏览器。这与传统的客户端渲染(CSR)不同,后者仅发送基本HTML结构和JavaScript文件,然后在用户浏览器中构建页面内容。

备注

SSR不是一个新概念!在JavaScript框架流行之前,大多数网站都使用服务端渲染(如PHP、JSP等)。现代SSR是将这一概念应用到JavaScript框架生态中。

SSR与CSR的区别

让我们通过一个简单的流程图来理解SSR和CSR(客户端渲染)的区别:

为什么需要SSR?

SSR主要解决了以下几个问题:

  1. 首屏加载速度: 用户无需等待JavaScript下载和执行即可看到页面内容
  2. 搜索引擎优化(SEO): 搜索引擎可以直接爬取完整的HTML内容
  3. 性能优化: 减轻客户端设备的计算负担,特别是在低端设备上
  4. 社交媒体分享: 提供完整的元数据,使分享链接能显示丰富预览

SSR的工作原理

让我们深入了解SSR的基本工作流程:

  1. 用户请求: 用户在浏览器中请求一个页面
  2. 服务端处理: 服务器接收请求,运行JavaScript代码
  3. 页面生成: 服务器执行渲染逻辑,生成完整的HTML
  4. 发送HTML: 服务器将完整的HTML发送给浏览器
  5. 客户端激活(Hydration): 浏览器下载JavaScript,"激活"已渲染的HTML使其具有交互性

水合(Hydration)是什么?

水合(Hydration)是SSR的关键概念,指的是客户端JavaScript"接管"服务器渲染的HTML,添加事件监听器使页面变得可交互。

提示

可以将水合过程想象成给"干"HTML注入"水分"(JavaScript交互性),使其"活"起来!

实现SSR的方式

1. 手动实现SSR

下面是一个使用Node.js和React手动实现SSR的简单示例:

jsx
// server.js
import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './App';

const app = express();

app.get('/', (req, res) => {
// 在服务器上渲染React组件
const appHtml = renderToString(<App />);

// 将渲染的HTML嵌入到完整的HTML文档中
const html = `
<!DOCTYPE html>
<html>
<head>
<title>React SSR示例</title>
</head>
<body>
<div id="root">${appHtml}</div>

<!-- 这个脚本将在客户端进行水合 -->
<script src="/client.js"></script>
</body>
</html>
`;

res.send(html);
});

app.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});
jsx
// client.js
import React from 'react';
import { hydrate } from 'react-dom';
import App from './App';

// 水合过程 - 为服务端渲染的HTML添加交互性
hydrate(<App />, document.getElementById('root'));

2. 使用现代框架实现SSR

现代JavaScript框架提供了更简单的SSR实现方式:

Next.js (React)

jsx
// pages/index.js
export default function Home() {
return (
<div>
<h1>Hello from Next.js SSR!</h1>
<p>这个页面是服务端渲染的</p>
</div>
)
}

// 可选: 获取数据
export async function getServerSideProps() {
// 从API获取数据
const res = await fetch('https://api.example.com/data');
const data = await res.json();

// 将数据作为props传递给页面
return { props: { data } }
}

Nuxt.js (Vue)

vue
<!-- pages/index.vue -->
<template>
<div>
<h1>Hello from Nuxt.js SSR!</h1>
<p>这个页面是服务端渲染的</p>
<div v-if="data">
{{ data }}
</div>
</div>
</template>

<script>
export default {
async asyncData({ $fetch }) {
const data = await $fetch('https://api.example.com/data')
return { data }
}
}
</script>

SSR的优缺点

优点

  1. 更快的首屏加载时间: 用户立即看到内容,无需等待JS执行
  2. 更好的SEO: 搜索引擎可以直接爬取完整的HTML内容
  3. 更好的社交媒体分享体验: 分享链接会显示完整的预览内容
  4. 更好的性能体验: 特别是在低端设备和慢网络环境下

缺点

  1. 服务器负载增加: 渲染发生在服务器上,增加了服务器的计算负担
  2. 开发复杂性: 需要同时考虑服务端和客户端的代码执行环境
  3. 缓存挑战: 动态内容难以有效缓存
  4. 首字节时间(TTFB)可能更长: 服务器需要时间生成完整HTML

SSR的实际应用场景

电子商务网站

电商网站需要良好的SEO和快速的首屏加载时间,同时产品详情页面内容丰富,非常适合SSR。

jsx
// 产品详情页面示例 (Next.js)
export default function ProductPage({ product }) {
return (
<div className="product-container">
<h1>{product.name}</h1>
<div className="product-image">
<img src={product.imageUrl} alt={product.name} />
</div>
<div className="product-info">
<p className="price">${product.price}</p>
<p className="description">{product.description}</p>
<button className="buy-button">加入购物车</button>
</div>
</div>
)
}

export async function getServerSideProps({ params }) {
// 获取产品ID
const { id } = params;

// 从API获取产品数据
const res = await fetch(`https://api.store.com/products/${id}`);
const product = await res.json();

return { props: { product } }
}

新闻/博客网站

内容丰富的新闻网站需要良好的SEO和社交媒体分享体验,SSR可以提供这些功能。

企业营销网站

企业网站通常需要优化搜索引擎排名,使用SSR可以确保内容被搜索引擎完全索引。

SSR相关概念

SSG (静态站点生成)

静态站点生成是SSR的一个变体,它在构建时而不是请求时生成HTML。适用于内容不经常变化的网站。

ISR (增量静态再生)

结合了SSG和SSR的优点,预渲染页面但允许在后台定期重新生成。Next.js等框架支持此功能。

jsx
// Next.js ISR示例
export async function getStaticProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();

return {
props: { data },
// 每10秒重新生成一次
revalidate: 10,
}
}

如何选择是否使用SSR?

考虑以下因素:

  • 网站的SEO需求是否关键?
  • 首屏加载速度是否极其重要?
  • 内容是否需要频繁更新?
  • 是否有足够的服务器资源?
  • 开发团队是否熟悉SSR相关技术?
警告

SSR并非适合所有应用。对于内部工具、管理面板或高度交互性的单页应用,客户端渲染可能更合适。

实践练习

练习1: 使用Next.js创建一个SSR页面

  1. 安装Next.js:
bash
npx create-next-app my-ssr-app
cd my-ssr-app
  1. 创建一个SSR页面:
jsx
// pages/ssr-demo.js
export default function SSRDemo({ serverTime }) {
return (
<div>
<h1>SSR示例页面</h1>
<p>这个页面是在服务器上渲染的</p>
<p>服务器时间: {serverTime}</p>
</div>
)
}

export async function getServerSideProps() {
return {
props: {
serverTime: new Date().toISOString()
}
}
}
  1. 运行应用:
bash
npm run dev
  1. 访问 http://localhost:3000/ssr-demo 查看结果

练习2: 比较CSR和SSR

创建两个页面,一个使用CSR,一个使用SSR,然后比较:

  • 首屏加载时间
  • 查看源代码中的内容差异
  • 禁用JavaScript后页面表现

总结

服务端渲染(SSR)是一种强大的渲染策略,可以帮助解决现代Web应用中的首屏加载和SEO问题。通过在服务器上生成完整的HTML并发送给客户端,SSR提供了更好的用户体验和搜索引擎可见性。

虽然SSR增加了开发复杂性和服务器负载,但对于内容丰富的网站和需要良好SEO的应用来说,其优势通常大于缺点。现代框架如Next.js和Nuxt.js使实现SSR变得更加简单。

在选择渲染策略时,务必根据项目具体需求权衡利弊,选择最适合的方案。

进一步学习资源

尝试通过以上资源进一步探索SSR的高级功能和优化技术,如流式SSR、部分水合、同构数据获取等。愿你的SSR学习之旅顺利!