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

如何用Node.js原生HTTP服务器搭建Vite SSR应用?求解报错问题

用Node.js原生HTTP服务器搭建Vite SSR的问题修复方案

Node.js原生HTTP服务器完全可以用于构建Vite SSR应用,你遇到的两个错误都是代码逻辑问题导致的,以下是具体修复步骤:

1. 解决WebSocket端口占用错误

问题原因

你把createViteServer放在了请求监听器requestListener内部,每次收到HTTP请求都会重新创建一个Vite服务器实例,重复启动HMR所需的WebSocket服务,导致端口被重复占用。

修复代码

将Vite服务器的初始化逻辑移到请求监听器外部,确保只初始化一次:

import { createServer } from 'http'
import { createViteServer } from 'vite'
import fs from 'fs'
import path from 'path'

const port = 3000
const host = 'localhost'

// 全局初始化Vite服务器,仅执行一次
const vite = await createViteServer({
  server: { middlewareMode: true },
  appType: 'custom'
})

const requestListener = async function (req, res) {
  // 后续处理逻辑...
}

const server = createServer(requestListener)
server.listen(port, host, () => {
  console.log(`Server is running on http://${host}:${port}`)
})

2. 解决模块脚本MIME类型错误

问题原因

当前代码对所有请求一律返回HTML内容,包括JS模块、静态资源等请求。浏览器请求entry-client.js时,服务器返回的是text/html类型的响应,不符合JS模块的MIME类型要求,因此触发报错。

修复代码

优先让Vite的中间件处理开发环境下的资源请求(如模块编译、HMR、静态资源),只有当Vite中间件无法处理时,才执行SSR渲染逻辑。由于原生HTTP服务器不直接支持connect风格中间件,需要用vite.middlewares.handle方法适配:

const requestListener = async function (req, res) {
  try {
    // 先用Vite中间件处理开发相关请求
    await new Promise((resolve, reject) => {
      vite.middlewares(req, res, (err) => {
        if (err) reject(err)
        resolve()
      })
    })

    // 处理SSR渲染
    const url = req.url
    let template = fs.readFileSync(
      path.resolve(__dirname, 'index.html'),
      'utf-8'
    )
    template = await vite.transformIndexHtml(url, template)

    const render = (await vite.ssrLoadModule('/src/entry-server.js')).render
    const { appHtml } = await render(url)

    const html = template.replace(`{{ appHtml }}`, appHtml)

    res.setHeader('Content-Type', 'text/html')
    res.writeHead(200)
    res.end(html)
  } catch (e) {
    vite.ssrFixStacktrace(e)
    console.error(e)
    res.writeHead(500)
    res.end(e.message)
  }
}

完整修复后的代码

import { createServer } from 'http'
import { createViteServer } from 'vite'
import fs from 'fs'
import path from 'path'

const port = 3000
const host = 'localhost'

// 全局初始化Vite服务器,避免重复创建实例
const vite = await createViteServer({
  server: { middlewareMode: true },
  appType: 'custom'
})

const requestListener = async function (req, res) {
  try {
    // 优先处理Vite负责的开发请求
    await new Promise((resolve, reject) => {
      vite.middlewares(req, res, (err) => {
        if (err) reject(err)
        resolve()
      })
    })

    // SSR渲染逻辑
    const url = req.url
    let template = fs.readFileSync(
      path.resolve(__dirname, 'index.html'),
      'utf-8'
    )
    template = await vite.transformIndexHtml(url, template)

    const render = (await vite.ssrLoadModule('/src/entry-server.js')).render
    const { appHtml } = await render(url)

    const html = template.replace(`{{ appHtml }}`, appHtml)

    res.setHeader('Content-Type', 'text/html')
    res.writeHead(200)
    res.end(html)
  } catch (e) {
    vite.ssrFixStacktrace(e)
    console.error(e)
    res.writeHead(500)
    res.end(e.message)
  }
}

const server = createServer(requestListener)
server.listen(port, host, () => {
  console.log(`Server is running on http://${host}:${port}`)
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:37:16