You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vite+React SSR配置异常:访问本地服务时浏览器无响应

Vite React SSR 服务端无响应问题排查

问题描述

我正在尝试基于Vite实现React SSR(服务端渲染),过程中遇到了问题:server.js可以正常启动(但存在警告),当访问本地服务localhost:3001时,浏览器一直处于加载状态,无法获取响应。
我在server.js中使用了h3、sirv和listhen工具,同时搭配react-router-dom 6.4。在await前添加console.log可以正常输出,说明服务在等待HTTP请求,但浏览器始终没有收到响应。我怀疑问题出在server.js中,现已附上相关代码及运行npm run dev时的终端输出,想请教哪里配置出错了?是否和server.js中的异步代码有关?

假设你的server.js核心代码如下:

import { createApp, defineEventHandler, createRouter } from 'h3'
import { renderToString } from 'react-dom/server'
import { StaticRouterProvider, createStaticHandler, createMemoryRouter } from 'react-router-dom/server'
import sirv from 'sirv'
import { listen } from 'listhen'
import App from './src/App'

const app = createApp()
app.use(sirv('dist/client', { dev: true }))

const router = createRouter()
router.get('*', defineEventHandler(async (event) => {
  const staticHandler = createStaticHandler(App.routes)
  const context = await staticHandler.query({ request: event.node.req })

  const memoryRouter = createMemoryRouter(App.routes, {
    initialEntries: [event.node.req.url],
    initialIndex: 0
  })

  const html = renderToString(
    <StaticRouterProvider router={memoryRouter} context={context} />
  )
  // 此处可能未返回响应
}))

app.use(router)
listen(toNodeListener(app), { port: 3001 })

终端运行输出示例:

> npm run dev

> dev
> node server.js

Listening on http://localhost:3001
(node:12345) Warning: Some warning message here
(Use `node --trace-warnings ...` to show where the warning was created)

核心问题排查与修复

1. 未主动返回HTTP响应

这是最常见的原因:你的代码执行了renderToString生成HTML,但没有调用h3的send()方法或event.res.end()结束请求,导致浏览器一直等待响应。

修复方式:在路由处理函数末尾添加响应返回逻辑:

return send(event, `
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>React SSR</title>
</head>
<body>
  <div id="root">${html}</div>
  <script type="module" src="/src/client.js"></script>
</body>
</html>
`, { headers: { 'Content-Type': 'text/html; charset=utf-8' } })

2. React Router 6.4 服务端逻辑遗漏

使用createStaticHandler和createMemoryRouter时,必须处理重定向、404等场景,否则请求会被挂起:

// 处理重定向
if (context.status === 301 || context.status === 302) {
  event.node.res.writeHead(context.status, { Location: context.headers.get('Location') })
  event.node.res.end()
  return
}

// 处理404
if (context.status === 404) {
  event.node.res.writeHead(404)
  event.node.res.end('<h1>404 Not Found</h1>')
  return
}

3. 异步代码未捕获错误

如果路由处理函数中有未捕获的异步错误,会导致请求无响应。添加try/catch块捕获并返回错误响应:

router.get('*', defineEventHandler(async (event) => {
  try {
    // 现有SSR逻辑
  } catch (err) {
    console.error('SSR渲染错误:', err)
    event.node.res.writeHead(500)
    event.node.res.end('<h1>Internal Server Error</h1>')
  }
}))

4. 静态文件服务与路由顺序错误

确保静态文件服务的app.use(sirv(...))放在路由处理之前,否则静态资源请求会被路由捕获,导致客户端脚本无法加载:

// 先挂载静态文件服务
app.use(sirv('dist/client', { dev: true }))
// 再挂载路由
app.use(router)

修复后完整路由处理示例

router.get('*', defineEventHandler(async (event) => {
  try {
    const staticHandler = createStaticHandler(App.routes)
    const context = await staticHandler.query({
      request: event.node.req,
      params: event.params
    })

    // 处理重定向
    if (context.status === 301 || context.status === 302) {
      event.node.res.writeHead(context.status, { Location: context.headers.get('Location') })
      event.node.res.end()
      return
    }

    // 处理404
    if (context.status === 404) {
      event.node.res.writeHead(404)
      event.node.res.end('<h1>404 Not Found</h1>')
      return
    }

    const memoryRouter = createMemoryRouter(App.routes, {
      initialEntries: [event.node.req.url],
      initialIndex: 0
    })

    const html = renderToString(
      <StaticRouterProvider router={memoryRouter} context={context} />
    )

    // 返回完整HTML
    return send(event, `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React SSR App</title>
</head>
<body>
  <div id="root">${html}</div>
  <script type="module" src="/src/main.jsx"></script>
</body>
</html>
`, { headers: { 'Content-Type': 'text/html; charset=utf-8' } })
  } catch (err) {
    console.error('SSR Error:', err)
    event.node.res.writeHead(500)
    event.node.res.end('<h1>Internal Server Error</h1>')
  }
}))

额外调试建议

  • 打开浏览器开发者工具的网络面板,查看请求状态码和响应内容,确认是服务端未返回响应还是返回了错误内容
  • 检查终端是否有未捕获的错误日志,异步错误可能没有被自动打印
  • 验证Vite客户端构建配置,确保客户端脚本路径正确可访问

内容的提问来源于stack exchange,提问作者Peter Devlin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 11:17:38