ReactDOMServer.renderToString返回空HTML,SSR页面root节点无渲染内容
问题根因
代码中的逻辑冲突和冗余配置直接导致SSR渲染逻辑完全未执行:
- 你在
serverRenderer函数内部额外定义了app.get('/*')路由,该路由会直接返回未经过内容替换的静态index.html文件,优先级高于后续的文件读取替换逻辑,导致renderToString相关代码完全没有机会运行 - 当前路由配置仅匹配根路径
^/$走SSR逻辑,访问其他路径时会直接返回静态html文件 - 服务端渲染场景下不需要使用
PersistGate组件,该组件是客户端持久化缓存专用,服务端无本地存储环境,可能会导致渲染返回null内容
修复方案
步骤1:删除冗余路由
直接删掉serverRenderer函数内部的app.get('/*')整段代码,这段逻辑和SSR需求完全冲突。
步骤2:移除服务端的PersistGate
服务端渲染只需要保留Provider和StaticRouter包裹即可,PersistGate仅在客户端hydrate逻辑中使用。
步骤3:调整路由匹配规则(需要全路径SSR时修改)
如果需要所有路径都走SSR渲染,要把静态资源托管逻辑放在SSR路由之前,避免静态资源请求被SSR逻辑拦截。
修复后完整代码
const PORT = 3000 const express = require('express') const path = require('path') const fs = require('fs') const React = require('react') const ReactDOMServer = require('react-dom/server') const { Provider } = require('react-redux') const { StaticRouter } = require('react-router-dom/server') const { store } = createPersistor() const App = require('./src/App').default const app = express() const router = express.Router() // 静态资源托管放在最前面,匹配到静态资源直接返回 router.use( express.static(path.resolve(__dirname, '..', 'build'), { index: false }) ) const serverRenderer = (req, res, next) => { const context = {} fs.readFile(path.resolve('./build/index.html'), 'utf8', (err, data) => { if (err) { console.error(err) return res.status(500).send('An error occurred') } const appHtml = ReactDOMServer.renderToString( <Provider store={store}> <StaticRouter location={req.url} context={context}> <App /> </StaticRouter> </Provider> ) return res.send( data.replace( '<div id="root"></div>', `<div id="root">${appHtml}</div>` ) ) }) } // 所有未匹配到静态资源的请求都走SSR渲染 router.use(serverRenderer) app.use(router) app.listen(PORT, () => { console.log(`SSR running on port ${PORT}`) })
验证
修改完成后重启服务,再次查看页面源码,id=root的div节点内就会存在服务端渲染出来的HTML内容。
内容的提问来源于stack exchange,提问作者shanksu 218
相关产品推荐
相关产品推荐

