javascript服务端渲染如何实现_node.js中怎样渲染前端页面【教程】
技术百科
夜晨
发布时间:2026-01-28
浏览: 次 SSR在Node.js中需手动控制HTML组装与响应流程:用fs.readFileSync读取含占位符的HTML,字符串替换后通过res.send()返回;Express需配置模板引擎才能使用res.render();React/Vue SSR本质是生成HTML字符串并注入初始状态,难点在于数据获取、样式隔离、路由一致性和hydration匹配。
服务端渲染(SSR)在 Node.js 中不是靠某个“开箱即用”的函数自动完成的,而是由你控制模板拼接时机、数据注入方式和响应流程——核心在于 res.send() 或 res.end() 之前,把 HTML 字符串组装好。
用 fs.readFileSync + 字符串替换是最简 SSR 实现
适合静态结构强、变量少的页面,比如带用户名称的欢迎页。不依赖框架,纯原生 Node.js 即可跑通:
- 读取一个含占位符的 HTML 文件,例如
index.html中写Hello, {{name}}
- 用
fs.readFileSync('./index.html', 'utf8')读成字符串 - 调用
.replace(/{{name}}/g, userName)替换内容 - 最后用
res.setHeader('Content-Type', 'text/html')+res.send(htmlStr)
注意:不能用 fs.readFile(异步)直接链式调用,否则 res.send() 会先执行,导致空响应或报错 Error [ERR_HTTP_HEADERS_SENT]。
express 配合 res.render() 需要显式注册模板引擎
Express 默认不内置任何模板引擎,res.render() 报 Error: No default engine was specified 就是因为没设 app.set('view engine', ...):
立即学习“Java免费学习笔记(深入)”;
- 装对应引擎,如
npm install ejs,然后app.set('view engine', 'ejs') - 设视图目录:
app.set('views', path.join(__dirname, 'views')) -
res.render('home', { title: 'My App', user: req.user })才能生效 - 若用
pug,后缀是.pug;用handlebars,需额外配express-handlebars
常见坑:文件扩展名和 view engine 值不一致(比如设了 'ejs' 却传 'home.hbs'),会导致 404 或 ENOENT 错误

React/Vue 的 SSR 不是“渲染页面”,而是“生成 HTML 字符串”
所谓 React SSR,本质是调用 ReactDOMServer.renderToString() 得到一段 HTML 字符串,再塞进模板里返回给客户端:
- Node 端不能用
ReactDOM.createRoot().render()—— 这是浏览器 API,服务端没有document - 必须用
renderToString()或renderToPipeableStream()(流式) - 生成的 HTML 要嵌入完整模板中,比如把
$$html$$替换成结果,并补上加载客户端 JS - 状态同步关键:用
window.__INITIAL_STATE__ = {...}注入 JSON,前端启动时读取,避免两次请求
漏掉状态同步或脚本加载逻辑,页面会闪动、交互失效,或者数据对不上。
真正难的不是“怎么把 HTML 发出去”,而是数据获取时机、样式隔离、路由匹配一致性、以及 hydration 时 DOM 树是否完全匹配——这些细节一旦出错,SSR 就退化成白屏或双端不一致。
# js
# json
# Error
# javascript
# java
# html
# 字符串
# node
# 前端
# node.js
# react
# npm
# express
# vue
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Windows10无法识别USB设备描述符请求失败
- Win11怎么关闭触控板_Win11笔记本禁用触摸
- php嵌入式多设备通信怎么实现_php同时管理多个
- Win11时间不对怎么同步_Win11自动校准互联
- 如何优化Golang程序CPU性能_Golang
- 如何使用Golang处理静态文件缓存_提高页面加载
- Linux怎么修改用户密码_Linux系统pass
- 如何使用Golang编写单元测试_创建Test函数
- Python路径拼接规范_跨平台处理说明【指导】
- php增删改查报错1054怎么办_字段名错误排查修
- Win11讲述人怎么关闭_Win11误触开启语音朗
- php打包exe怎么传递参数_命令行参数接收方法【
- Windows 10怎么把任务栏放在屏幕上方_Wi
- Python对象生命周期管理_创建销毁解析【教程】
- PythonGIL机制理解_多线程限制解析【教程】
- Win11怎么连接蓝牙耳机_Win11蓝牙设备配对
- c++ nullptr与NULL区别_c++11空
- c++怎么实现高并发下的无锁队列_c++ std:
- Windows10系统服务优化指南_Win10禁用
- Win11如何连接Xbox手柄 Win11蓝牙连接
- Windows10如何更改鼠标灵敏度_Win10鼠
- c++协程和线程的区别 c++异步编程模型对比【核
- php中::能访问全局变量吗_全局作用域与类作用域
- Avalonia如何实现跨窗口通信 Avaloni
- MAC如何隐藏文件夹及文件_MAC终端命令隐藏与第
- 如何在 Windows 11 中使用 AlomWa
- Python实现图数据库操作_Neo4j核心CRU
- Windows怎样关闭开始菜单广告_Windows
- Win10文件历史记录怎么用 Win10开启自动备
- mac怎么打开终端_MAC终端Terminal使用
- 如何在 Go 中正确初始化结构体中的 map 字段
- Win11怎么设置默认浏览器Chrome_Wind
- windows 10专注助手怎么关闭_window
- Win11怎么快速锁屏_Win11一键锁屏快捷键W
- 如何在Golang中使用encoding/gob序
- Win11怎么设置单手模式_Win11触控键盘布局
- Mac怎么开启“任何来源”_Mac安装未签名应用的
- Win11文件夹预览图不显示怎么办_Win11缩略
- Win10如何更改电脑休眠时间_Windows10
- c++如何实现多态性_c++ 虚函数表原理与动态绑
- Mac怎么设置登录项_Mac管理开机自启动程序【教
- Win11怎么关闭透明效果_Windows11个性
- c++怎么实现大文件的分块读写_c++ 文件指针s
- Win11如何更改用户账户文件夹名称 Win11修
- php中::能用于接口静态方法吗_接口静态方法调用
- 如何在JavaScript中动态拼接PHP的bas
- Python模块的__name__属性如何由导入方
- Windows资源管理器总是卡顿或重启怎么办?(修
- php在Linux怎么部署_LNMP环境搭建PHP
- 如何在Windows中创建新的用户账户?(标准与管

QQ客服