
Vercel 不支持长期运行的 WebSocket 服务器,因其 Serverless 函数无状态、有超时限制;若需实现实时协同(如多人白板),必须将 Socket.IO 后端托管至支持长连接的平台(如 Railway、Render 或 AWS EC2),前端仍可继续部署在 Vercel。
vercel 不支持长期运行的 websocket 服务器,因其 serverless 函数无状态、有超时限制;若需实现实时协同(如多人白板),必须将 socket.io 后端托管至支持长连接的平台(如 railway、render 或 aws ec2),前端仍可继续部署在 vercel。
在构建实时协作类应用(例如多人同步白板)时,Socket.IO 是常用的技术方案:前端通过 io.connect() 建立持久 WebSocket 连接,后端监听 connection、beginpath、drawstroke 等事件,并广播给所有客户端。然而,当尝试将完整全栈项目(含 Express + Socket.IO 后端)直接部署到 Vercel 时,必然失败——这不是配置问题,而是平台能力的根本限制。
❌ 为什么 Vercel 无法运行 Socket.IO 后端?
根据 Vercel 官方文档 明确说明:
“Serverless Functions on Vercel are stateless and have a maximum execution duration. As a result, it is not possible to maintain a WebSocket connection to a Serverless Function.”
即:
- Vercel 的函数是无状态、短生命周期的(最大运行时间通常为 10–60 秒);
- WebSocket 连接要求服务端进程持续存活、维持 socket 实例和内存状态;
- socket.io 依赖 http.Server 实例长期监听,而 Vercel 不提供常驻 Node.js 服务环境。
因此,你当前的后端代码(含 app.listen() 和 socket(server))在 Vercel 上根本无法启动或保持连接,浏览器控制台会报类似错误:
WebSocket connection to 'wss://white-board-zeta.vercel.app/' failed
✅ 正确部署架构:前后端分离 + 独立 WebSocket 托管
推荐采用「前端静态托管于 Vercel + 后端 WebSocket 服务独立部署」的架构:
| 组件 | 部署位置 | 说明 |
|---|---|---|
| index.html + canvas.js + tools.js + socket.io-client | ✅ Vercel | 作为纯静态站点,自动 CDN 加速,支持自定义域名与 HTTPS |
| server.js(Express + Socket.IO) | ✅ Railway / Render / Fly.io / EC2 | 提供长期运行的 HTTP/WebSocket 服务,需暴露公网 URL(如 https://whiteboard-backend.up.railway.app) |
? 前端适配(关键修改)
将前端 JS 中的硬编码地址替换为你的独立后端地址(注意协议:https:// → wss:// 自动升级):
<script>
// ❌ 错误:指向 Vercel 域名(不支持 WebSocket)
// let socket = io.connect("https://white-board-zeta.vercel.app/");
// ✅ 正确:指向你部署的 WebSocket 服务(如 Railway)
let socket = io.connect("https://whiteboard-backend.up.railway.app", {
transports: ["websocket"], // 强制使用 WebSocket,避免 xhr-polling
reconnection: true,
reconnectionAttempts: 5,
timeout: 10000
});
</script>
? 提示:确保后端已正确配置 CORS 与 WebSocket 跨域(见下文)。
⚙️ 后端加固配置(修复常见部署问题)
更新你的 server.js,显式启用跨域并增强健壮性:
const express = require("express");
const http = require("http"); // 显式引入 http,避免隐式依赖
const socketIo = require("socket.io");
const cors = require("cors");
const app = express();
const server = http.createServer(app); // 使用 http.Server 而非 app.listen()
// 允许指定前端域名(生产环境勿用 "*")
app.use(cors({
origin: ["https://white-board-zeta.vercel.app"], // 替换为你的 Vercel 域名
credentials: true
}));
// 静态资源仅服务于前端(可选:也可完全由 Vercel 托管)
app.use(express.static("./frontend"));
// Socket.IO 配置(关键:启用 WebSocket 并允许跨域)
const io = socketIo(server, {
cors: {
origin: ["https://white-board-zeta.vercel.app"],
methods: ["GET", "POST"],
credentials: true
},
transports: ["websocket"], // 优先 WebSocket
allowEIO3: true
});
io.on("connection", (socket) => {
console.log("✅ New client connected:", socket.id);
socket.on("beginpath", (data) => {
io.emit("beginpath", data); // 推荐用 io.emit() 代替 io.sockets.emit()
});
socket.on("drawstroke", (data) => {
io.emit("drawstroke", data);
});
socket.on("performUndoRedo", (data) => {
io.emit("performUndoRedo", data);
});
socket.on("disconnect", () => {
console.log("❌ Client disconnected:", socket.id);
});
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`? WebSocket server running on port ${PORT}`);
});
✅ 部署提示:在 Railway/Render 中,确保设置 PORT 环境变量,并将启动命令设为 node server.js。
? 注意事项与最佳实践
- 不要尝试“伪装”WebSocket:Vercel 的边缘网络会终止长连接,任何 setTimeout、setInterval 或 ws 模拟均无效;
- HTTPS/WSS 强制要求:浏览器在 HTTPS 页面中禁止建立 ws://(非加密)连接,务必使用 wss:// —— 所以你的后端必须配置 TLS(Railway/Render 默认提供免费证书);
- 连接稳定性:添加重连逻辑(如上例)、心跳检测(pingTimeout/pingInterval 可选配置);
- 安全加固:生产环境禁用 origin: "*",严格配置 cors.origin;对敏感操作(如清除画布)建议增加身份校验(JWT + 中间件);
- 调试技巧:本地用 ngrok http 3000 临时暴露本地服务,验证前后端通信是否正常,再迁移至云平台。
✅ 总结
Vercel 是优秀的前端托管平台,但不是通用 Node.js 服务器替代品。对于需要 WebSocket、长轮询、后台任务或状态维持的应用,必须解耦后端服务。将 Socket.IO 白板后端迁移到 Railway(免费 tier 支持 24/7 运行)只需 2 分钟:上传代码 → 设置 PORT → 点击 Deploy → 复制 URL → 更新前端连接地址 —— 即可实现真正实时、低延迟的多人协同体验。










