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

Vercel部署出现TypeError: server.listeners is not a function问题求助

解决Vercel部署时Socket.io的TypeError: server.listeners is not a function错误

问题描述

在Vercel部署应用时遇到TypeError: server.listeners is not a function错误,本地localhost环境运行正常,查阅相关问题未找到有效解决方案,以下是错误信息及后端代码。

错误信息

TypeError: server.listeners is not a function
at Server.attach (/var/task/api/node_modules/engine.io/build/server.js:642:34)
at attach (/var/task/api/node_modules/engine.io/build/engine.io.js:53:12)
at Server.initEngine (/var/task/api/node_modules/socket.io/dist/index.js:293:43)

⛁ MongoDb is connected ✅

后端代码

import express from "express";
import mongoose from "mongoose";
import dotenv from "dotenv";
import authRoutes from "./routes/auth.route.js";
import blogRoutes from "./routes/blog.route.js";
import resumeRoutes from "./routes/resume.route.js";
import chatRoutes from "./routes/chat.route.js";
import cookieParser from "cookie-parser";
import path from "path";
import bodyParser from "body-parser";
import { fileURLToPath } from 'url';
import http from "http";
import { Server } from 'socket.io';

dotenv.config();

mongoose.connect(process.env.MONGO)
  .then(() => {
    console.log("⛁ MongoDb is connected ✅");
  })
  .catch((err) => {
    console.error(err);
  });

const app = express();
const server = http.createServer(app);
const io = new Server(server);

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.json());
app.use(cookieParser());

app.use("/api/auth", authRoutes);
app.use("/api/blog", blogRoutes);
app.use("/api/resume", resumeRoutes);
app.use("/api/chats", chatRoutes);

io.on('connection', (socket) => {
  console.log('a user connected');

  socket.on('disconnect', () => {
    console.log('a user disconnected');
  });
});

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const distDirectory = path.join(__dirname, '../client/dist');
app.use(express.static(distDirectory));
app.get('/', (req, res) => {
  res.sendFile(path.join(distDirectory, 'index.html'));
});

app.use((err, req, res, next) => {
  const statusCode = err.statusCode || 500;
  const message = err.message || "Internal Server Error";
  console.error(message);
  res.status(statusCode).json({
    success: false,
    statusCode,
    message,
  });
});

server.listen(process.env.PORT || 3000, () => {
  console.log(`🚀 Server is running on port ${process.env.PORT || 3000} 🥳`);
});

export default io;

解决方案

核心原因

Vercel是无服务器平台,采用请求驱动的实例模式,不支持长期运行的HTTP服务器。传统的http.createServer()+server.listen()模式与该平台逻辑冲突,导致Socket.io无法正确绑定服务器实例。

具体步骤

  1. 安装Socket.io的Vercel适配包
npm install @socket.io/vercel
  1. 创建Socket.io专用API路由
    在项目中新建api/socket/io.js文件,内容如下:
import { Server } from "socket.io";
import { createServer } from "http";
import { VercelRequest, VercelResponse } from "@vercel/node";

const ioHandler = (req, res) => {
  // 复用服务器实例,避免重复初始化
  if (!res.socket.server.io) {
    const server = createServer((req, res) => {
      res.writeHead(404);
      res.end();
    });

    const io = new Server(server, {
      path: "/api/socket/io",
      addTrailingSlash: false,
    });

    io.on("connection", (socket) => {
      console.log("a user connected");
      socket.on("disconnect", () => {
        console.log("user disconnected");
      });
    });

    res.socket.server.io = io;
  }
  res.end();
};

export default ioHandler;
  1. 修改主服务器代码
    移除原代码中的HTTP服务器创建、Socket.io初始化及server.listen逻辑,改为导出Express应用:
import express from "express";
import mongoose from "mongoose";
import dotenv from "dotenv";
import authRoutes from "./routes/auth.route.js";
import blogRoutes from "./routes/blog.route.js";
import resumeRoutes from "./routes/resume.route.js";
import chatRoutes from "./routes/chat.route.js";
import cookieParser from "cookie-parser";
import path from "path";
import bodyParser from "body-parser";
import { fileURLToPath } from 'url';

dotenv.config();

mongoose.connect(process.env.MONGO)
  .then(() => {
    console.log("⛁ MongoDb is connected ✅");
  })
  .catch((err) => {
    console.error(err);
  });

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.json());
app.use(cookieParser());

app.use("/api/auth", authRoutes);
app.use("/api/blog", blogRoutes);
app.use("/api/resume", resumeRoutes);
app.use("/api/chats", chatRoutes);

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const distDirectory = path.join(__dirname, '../client/dist');
app.use(express.static(distDirectory));
app.get('/', (req, res) => {
  res.sendFile(path.join(distDirectory, 'index.html'));
});

app.use((err, req, res, next) => {
  const statusCode = err.statusCode || 500;
  const message = err.message || "Internal Server Error";
  console.error(message);
  res.status(statusCode).json({
    success: false,
    statusCode,
    message,
  });
});

export default app;
  1. 配置Vercel路由规则
    在项目根目录创建vercel.json文件,添加路由配置:
{
  "routes": [
    {
      "src": "/api/socket/io",
      "dest": "/api/socket/io.js",
      "methods": ["GET", "POST", "OPTIONS"]
    },
    {
      "src": "/(.*)",
      "dest": "/api/index.js"
    }
  ]
}

前端连接调整

前端连接Socket.io时,需要指向新的API路径:

import { io } from "socket.io-client";

const socket = io({
  path: "/api/socket/io"
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 13:02:37