如何解决NuxtJS 3 Nitro服务器中Socket.io仅开发环境可用问题
Nuxt 3 Nitro + Socket.io 生产环境WebSocket无响应问题解决
问题背景
在NuxtJS 3的Nitro服务器中集成Socket.io时,开发模式下WebSocket功能正常,但部署到生产环境后无法接收响应,怀疑是端口未与HTTP服务器保持一致导致。
原module/socket.ts代码:
import { Server } from 'socket.io' import { defineNuxtModule } from '@nuxt/kit' const clients: any = {}; export default defineNuxtModule({ setup(options, nuxt) { nuxt.hook('listen', (server) => { console.log('Socket listen', server.address(), server.eventNames()) const io = new Server(server) nuxt.hook('close', () => io.close()) io.on('connection', (socket) => { console.log('new connection', socket.id) clients[socket.id] = socket.handshake.query.clientId; }) io.on('connect', (socket) => { socket.on('message', function message(data: any) { console.log('message received: %s', data) const customId = Object.keys(clients).find(key => clients[key] === data['id']); if (customId) { console.log('sending to', customId) socket.to(customId).emit('widget', data) } }) socket.on('disconnecting', () => { console.log('disconnected', socket.id) delete clients[socket.id]; }) }); }) }, })
解决方案
1. 统一端口与生产环境地址绑定
- Nitro在生产环境可能通过环境变量指定端口(如
PORT),Socket.io直接绑定到Nitro传入的server实例即可确保共用同一端口,无需额外配置端口。 - 客户端连接时不要硬编码
localhost:3000,需根据环境动态生成地址:开发环境用window.location.origin,生产环境自动适配部署域名。
2. 添加生产环境必要的Socket.io配置
生产环境需配置CORS(避免跨域拦截),并明确Socket.io的路径(防止与Nitro路由冲突),修改Socket.io初始化代码:
const io = new Server(server, { cors: { origin: process.env.NODE_ENV === 'production' ? process.env.NUXT_PUBLIC_APP_URL : '*', methods: ['GET', 'POST'] }, path: '/socket.io/' })
3. 合并重复的连接事件监听
原代码同时监听connection和connect(二者为同一事件),会导致逻辑重复执行,合并为单个监听:
io.on('connection', (socket) => { console.log('new connection', socket.id) clients[socket.id] = socket.handshake.query.clientId; // 处理message事件 socket.on('message', function message(data: any) { console.log('message received: %s', data) const customId = Object.keys(clients).find(key => clients[key] === data['id']); if (customId) { console.log('sending to', customId) socket.to(customId).emit('widget', data) } }) // 处理断开连接 socket.on('disconnecting', () => { console.log('disconnected', socket.id) delete clients[socket.id]; }) })
4. 确认生产环境反向代理配置(若使用)
如果生产环境用Nginx等反向代理,需配置WebSocket支持:
location /socket.io/ { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; }
修正后的完整module/socket.ts代码
import { Server } from 'socket.io' import { defineNuxtModule } from '@nuxt/kit' const clients: Record<string, string> = {}; export default defineNuxtModule({ setup(options, nuxt) { nuxt.hook('listen', (server) => { console.log('Socket listen', server.address(), server.eventNames()) // 配置生产环境CORS和路径 const io = new Server(server, { cors: { origin: process.env.NODE_ENV === 'production' ? process.env.NUXT_PUBLIC_APP_URL : '*', methods: ['GET', 'POST'] }, path: '/socket.io/' }) nuxt.hook('close', () => io.close()) io.on('connection', (socket) => { console.log('new connection', socket.id) const clientId = socket.handshake.query.clientId as string; if (clientId) { clients[socket.id] = clientId; } socket.on('message', (data: any) => { console.log('message received: %o', data) const customId = Object.keys(clients).find(key => clients[key] === data.id); if (customId) { console.log('sending to', customId) socket.to(customId).emit('widget', data) } }) socket.on('disconnecting', () => { console.log('disconnected', socket.id) delete clients[socket.id]; }) }) }) }, })
内容的提问来源于stack exchange,提问作者Bruno Belloni
相关产品推荐
相关产品推荐

