服务器端渲染(SSR)指的是在服务器端完成页面的HTML结构生成,再直接将完整HTML返回给客户端,相比客户端渲染能大幅提升首屏加载速度,也更利于搜索引擎抓取页面内容。Node.js提供了JavaScript的运行环境,Express.js是轻量灵活的Node.js Web框架,二者结合可以高效实现SSR功能。

环境准备与依赖安装
首先创建项目目录并初始化,然后安装核心依赖:
mkdir ssr-demo && cd ssr-demo npm init -y npm install express react react-dom npm install -D @babel/core @babel/preset-env @babel/preset-react babel-register
这里需要Babel是因为服务端运行的Node.js默认不支持JSX语法,需要通过Babel转译。在项目根目录创建.babelrc配置文件:
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
创建React组件与入口文件
先编写一个简单的React组件,作为渲染的内容载体:
// src/App.jsx
import React from "react";
const App = (props) => {
return (
<div>
<h1>服务器端渲染示例</h1>
<p>当前服务端传递的数据:{props.message}</p>
<ul>
{props.list.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
};
export default App;
实现Express服务端渲染逻辑
创建服务端的入口文件,编写Express路由和SSR核心逻辑:
// server.js
require("babel-register");
const express = require("express");
const React = require("react");
const ReactDOMServer = require("react-dom/server");
const App = require("./src/App").default;
const app = express();
const PORT = 3000;
// 静态资源托管,用于加载客户端打包后的文件
app.use(express.static("public"));
app.get("/", (req, res) => {
// 模拟服务端预取的数据
const serverData = {
message: "来自服务端的数据",
list: ["节点1", "节点2", "节点3"]
};
// 将React组件渲染为HTML字符串
const appHtml = ReactDOMServer.renderToString(
React.createElement(App, serverData)
);
// 拼接完整的HTML模板,将组件HTML注入到页面中
const html = `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SSR示例页面</title>
</head>
<body>
<div id="root">${appHtml}</div>
<script>
// 将服务端数据挂载到window上,供客户端 hydrate 使用
window.__INITIAL_DATA__ = ${JSON.stringify(serverData)};
</script>
<script src="/client.bundle.js"></script>
</body>
</html>
`;
res.send(html);
});
app.listen(PORT, () => {
console.log(`服务运行在 http://127.0.0.1:${PORT}`);
});
客户端激活逻辑
SSR返回的是静态HTML,需要客户端加载JS后执行hydrate来绑定事件,实现页面可交互。创建客户端入口文件:
// src/client.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
// 获取服务端注入的初始数据
const initialData = window.__INITIAL_DATA__;
const root = ReactDOM.createRoot(document.getElementById("root"));
root.hydrate(
<App {...initialData} />
);
这里需要使用hydrate而不是render,它会复用服务端已经生成的DOM节点,不会重新创建,避免页面闪烁。
运行与验证
修改package.json的启动脚本:
{
"scripts": {
"start": "node server.js"
}
}
执行npm start启动服务,访问http://127.0.0.1:3000,查看页面源代码可以看到完整的HTML结构已经由服务端生成,首屏内容无需等待客户端JS加载即可展示。
核心注意点
- 服务端渲染的组件要避免使用
window、document等浏览器特有的API,这些API只在客户端存在,服务端调用会报错,如果必须使用可以通过判断环境来兼容。 - 数据预取需要在服务端路由匹配阶段完成,确保渲染组件时数据已经就绪,避免组件渲染时出现空数据。
- 客户端hydrate的数据要和服务端渲染时使用的数据保持一致,否则会出现 hydration 错误,页面内容可能不匹配。
Node.jsExpress.js服务器端渲染SSRReact修改时间:2026-07-17 11:00:14