SSR(服务端渲染)技术文档
一、SSR 概述
SSR(Server-Side Rendering,服务端渲染)是一种在服务端生成完整 HTML 页面,再发送给客户端渲染的前端渲染模式。与 CSR(客户端渲染,如 React/Vue 单页应用)不同,SSR 的核心是“服务端生成初始 DOM,客户端在此基础上激活交互”,旨在解决 CSR 首屏加载慢、SEO 不友好的问题,同时保留客户端交互的流畅性。
二、SSR 核心流程
SSR 的完整流程分为 服务端渲染阶段 和 客户端激活阶段(Hydration),两者协作完成页面的加载与交互。
- 服务端渲染阶段(服务端主导)
服务端是 SSR 的核心执行者,负责生成初始 HTML 并返回给客户端。具体步骤如下:
(1)接收请求,路由匹配
用户发起 HTTP 请求(如 GET /user/123),服务端(如 Node.js + Express/Koa、Nginx)通过路由中间件(如 Next.js 的 getServerSideProps、Nuxt.js 的 serverMiddleware)匹配请求路径,确定要渲染的页面组件。
(2)数据预取(Data Fetching)
服务端为组件获取渲染所需的动态数据(如用户信息、商品列表),数据来源包括:
数据库(MySQL、MongoDB);
外部 API(如用户服务接口 GET /api/user/123);
本地文件或缓存(Redis 缓存的静态数据)。
关键要求:服务端需在渲染前完成数据获取,确保 HTML 包含最新数据(如用户昵称、订单状态)。
(3)组件渲染(生成 HTML)
服务端使用前端框架(React、Vue)的渲染引擎(如 ReactDOMServer.renderToString、vue-server-renderer),将组件与预取的数据结合,生成完整的 HTML 字符串。
示例(React + Next.js):
在这里插入代码片
// 服务端渲染函数(Next.js 的 getServerSideProps)
export async function getServerSideProps(context) {
const { params } = context;
const userId = params.id;
// 数据预取:调用 API 获取用户信息
const user = await fetch(`https://api.example.com/users/${userId}`).then(res => res.json());
return { props: { user } }; // 传递给页面组件
}
// 页面组件
export default function UserPage({ user }) {
return (
<div>
<h1>{user.name}</h1>
<p>邮箱:{user.email}</p>
</div>
);
}
服务端执行后生成 HTML 字符串(如
张三
邮箱:zhangsan@example.com
(4)注入额外内容(可选)
服务端可能在 HTML 中注入:
全局元信息(
客户端脚本(如 ,用于客户端激活);
静态资源路径(CSS、图片的 CDN 地址)。
(5)返回 HTML 给客户端
服务端将生成的完整 HTML 字符串通过 HTTP 响应返回给客户端(状态码 200)。此时客户端收到的 HTML 已包含静态内容和交互所需的 JS 脚本链接。
- 客户端激活阶段(Hydration,客户端主导)
客户端(浏览器)接收到服务端返回的 HTML 后,需要将其“激活”为可交互的应用,这一过程称为 Hydration(注水)。
(1)解析 HTML,渲染静态内容
浏览器解析服务端返回的 HTML,构建 DOM 树和 CSSOM 树,渲染出可见的静态页面(如用户信息、商品列表)。此时页面内容已可见,但无交互能力(如点击按钮无响应)。
(2)加载客户端 JS 脚本
浏览器解析到 HTML 中的 ),发起请求加载客户端 JS 包(由 Webpack/Rollup 打包生成)。
(3)执行 JS,激活交互(Hydration)
客户端 JS 加载完成后,执行以下关键操作:
初始化应用:创建 React/Vue 根实例(如 ReactDOM.createRoot(document.getElementById(‘root’)));
绑定事件:将组件中的事件处理函数(如 onClick、onSubmit)绑定到 DOM 元素;
状态同步:将服务端渲染时的状态(如 user数据)同步到客户端状态管理(如 Redux/Vuex);
激活交互:使页面从“静态展示”变为“可交互”(如点击按钮触发 API 请求、表单提交等)。
关键要求:客户端 JS 需严格匹配服务端渲染的 DOM 结构(如 DOM 节点数量、数据状态),否则会导致“水合错误”(Hydration Mismatch),页面无法正常交互。
SSR(服务端渲染)技术文档
一、SSR 概述
SSR(Server-Side Rendering,服务端渲染)是一种在服务端生成完整 HTML 页面,再发送给客户端渲染的前端渲染模式。与 CSR(客户端渲染,如 React/Vue 单页应用)不同,SSR 的核心是“服务端生成初始 DOM,客户端在此基础上激活交互”,旨在解决 CSR 首屏加载慢、SEO 不友好的问题,同时保留客户端交互的流畅性。
二、SSR 核心流程
SSR 的完整流程分为 服务端渲染阶段 和 客户端激活阶段(Hydration),两者协作完成页面的加载与交互。
- 服务端渲染阶段(服务端主导)
服务端是 SSR 的核心执行者,负责生成初始 HTML 并返回给客户端。具体步骤如下:
(1)接收请求,路由匹配
用户发起 HTTP 请求(如 GET /user/123),服务端(如 Node.js + Express/Koa、Nginx)通过路由中间件(如 Next.js 的 getServerSideProps、Nuxt.js 的 serverMiddleware)匹配请求路径,确定要渲染的页面组件。
(2)数据预取(Data Fetching)
服务端为组件获取渲染所需的动态数据(如用户信息、商品列表),数据来源包括:
数据库(MySQL、MongoDB);
外部 API(如用户服务接口 GET /api/user/123);
本地文件或缓存(Redis 缓存的静态数据)。
关键要求:服务端需在渲染前完成数据获取,确保 HTML 包含最新数据(如用户昵称、订单状态)。
(3)组件渲染(生成 HTML)
服务端使用前端框架(React、Vue)的渲染引擎(如 ReactDOMServer.renderToString、vue-server-renderer),将组件与预取的数据结合,生成完整的 HTML 字符串。
示例(React + Next.js):
jsx
复制
// 服务端渲染函数(Next.js 的 getServerSideProps)
export async function getServerSideProps(context) {
const { params } = context;
const userId = params.id;
// 数据预取:调用 API 获取用户信息
const user = await fetch(https://api.example.com/users/${userId}
).then(res => res.json());
return { props: { user } }; // 传递给页面组件
}
// 页面组件
export default function UserPage({ user }) {
return (
{user.name}
邮箱:{user.email}
);
}
服务端执行后生成 HTML 字符串(如
张三
邮箱:zhangsan@example.com
(4)注入额外内容(可选)
服务端可能在 HTML 中注入:
全局元信息(
客户端脚本(如 ,用于客户端激活);
静态资源路径(CSS、图片的 CDN 地址)。
(5)返回 HTML 给客户端
服务端将生成的完整 HTML 字符串通过 HTTP 响应返回给客户端(状态码 200)。此时客户端收到的 HTML 已包含静态内容和交互所需的 JS 脚本链接。
- 客户端激活阶段(Hydration,客户端主导)
客户端(浏览器)接收到服务端返回的 HTML 后,需要将其“激活”为可交互的应用,这一过程称为 Hydration(注水)。
(1)解析 HTML,渲染静态内容
浏览器解析服务端返回的 HTML,构建 DOM 树和 CSSOM 树,渲染出可见的静态页面(如用户信息、商品列表)。此时页面内容已可见,但无交互能力(如点击按钮无响应)。
(2)加载客户端 JS 脚本
浏览器解析到 HTML 中的 ),发起请求加载客户端 JS 包(由 Webpack/Rollup 打包生成)。
(3)执行 JS,激活交互(Hydration)
客户端 JS 加载完成后,执行以下关键操作:
初始化应用:创建 React/Vue 根实例(如 ReactDOM.createRoot(document.getElementById(‘root’)));
绑定事件:将组件中的事件处理函数(如 onClick、onSubmit)绑定到 DOM 元素;
状态同步:将服务端渲染时的状态(如 user数据)同步到客户端状态管理(如 Redux/Vuex);
激活交互:使页面从“静态展示”变为“可交互”(如点击按钮触发 API 请求、表单提交等)。
关键要求:客户端 JS 需严格匹配服务端渲染的 DOM 结构(如 DOM 节点数量、数据状态),否则会导致“水合错误”(Hydration Mismatch),页面无法正常交互。
三、Nuxt.js 路由匹配机制(以 Nuxt 为例)
Nuxt.js 是基于 Vue.js 的 SSR 框架,其路由匹配机制结合了 Vue Router 的扩展与自动路由生成,核心逻辑如下:
- 路由配置自动生成
Nuxt 在构建阶段(npm run build)扫描 pages目录下的所有 .vue文件,根据文件路径自动生成路由配置(类似 Vue Router 的 routes数组)。
示例路由配置(自动生成)
在这里插入代码片
// nuxt 生成的路由配置(简化)
const routes = [
{ path: '/', component: '@/pages/index.vue' }, // 静态路由
{ path: '/user/:id', component: '@/pages/user/[id].vue' }, // 动态路由
{ path: '/blog/:slug/comments', component: '@/pages/blog/[slug]/comments.vue' }, // 嵌套动态路由
{ path: '*', component: '@/pages/404.vue' } // 通配符路由(404)
];
- 请求路径匹配流程
服务端接收到请求后,Nuxt 会将请求路径(如 /user/123)与自动生成的路由配置进行匹配,找到最长前缀匹配的路由规则(Vue Router 的默认匹配策略)。
示例匹配过程:
请求路径 /user/123→ 匹配 /user/:id(动态路由),提取参数 id=123,传递给对应的组件(pages/user/[id].vue)。
- serverMiddleware 的作用
serverMiddleware是 Nuxt 提供的服务端中间件钩子,用于在路由匹配前后执行自定义逻辑(如身份验证、请求修改、日志记录等)。它不直接参与路由匹配,但可以影响路由匹配的结果(如重定向、修改请求路径)。
示例:通过 serverMiddleware实现身份验证
在这里插入代码片
// nuxt.config.js
export default defineNuxtConfig({
serverMiddleware: [
async (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token || !validateToken(token)) {
return res.redirect('/login'); // 未登录则重定向
}
next(); // 验证通过,继续路由匹配
}
]
});
五、SSR 关键技术点
- 数据预取一致性
服务端需确保渲染时使用的数据与客户端 JS 加载后使用的数据一致(如避免数据过期)。
实现方式:通过 getServerSideProps(Next.js)或 asyncData(Nuxt)同步数据到组件 props。
- Hydration 匹配
客户端 JS 需严格匹配服务端渲染的 DOM 结构(如节点数量、属性、数据状态),否则会导致水合错误。
框架支持:React 的 hydrateRoot、Vue 的 createSSRApp会自动检查 DOM 一致性。
- 性能优化
缓存策略:缓存服务端渲染的 HTML(如使用 Redis),减少重复渲染。
流式渲染(Stream Rendering):分块发送 HTML,提升首屏加载速度(如 React 18 的 renderToPipeableStream)。
按需加载:仅对首屏关键组件进行 SSR,非关键组件延迟加载(如使用 React.lazy)。