如何在Next.js开发模式自定义服务中运行同端口WebSocket且不破坏热重载
Next.js 自定义服务WebSocket与热重载共存方案
核心实现思路
Next.js 开发模式的热重载功能固定使用路径为/_next/webpack-hmr的WebSocket连接,我们只需要手动接管HTTP服务的WebSocket升级请求,做路径分发即可:热重载相关的路径直接透传给Next.js原生逻辑处理,其余路径的请求走自定义WebSocket逻辑,完全不需要占用额外端口。
修改后的完整代码
const { createServer } = require('http') const WebSocket = require("ws") const { parse } = require('url') const next = require('next') const dev = process.env.NODE_ENV !== 'production' const port = process.env.PORT || 3000 const app = next({ dev }) const handle = app.getRequestHandler() app.prepare().then(() => { const server = createServer((req, res) => handle(req, res, parse(req.url, true))) // 初始化WebSocket服务时开启noServer模式,不自动绑定upgrade事件 const wss = new WebSocket.Server({ noServer: true }) wss.on("connection", async function connection(ws) { console.log('incoming connection', ws); ws.onclose = () => { console.log('connection closed', wss.clients.size); }; }); // 手动监听WebSocket升级请求,做路径分发 server.on('upgrade', (request, socket, head) => { const { pathname } = parse(request.url) // 跳过Next.js热重载专用的WebSocket路径,交给Next原生处理 if (pathname === '/_next/webpack-hmr') return // 其余路径交给自定义WebSocket服务处理 wss.handleUpgrade(request, socket, head, (ws) => { wss.emit('connection', ws, request) }) }) server.listen(port, (err) => { if (err) throw err console.log(`> Ready on http://localhost:${port} and ws://localhost:${port}`) }) })
关键逻辑说明
- 给
WebSocket.Server配置添加noServer: true,禁止WebSocket服务自动接管所有HTTP服务的升级请求 - 手动监听
server的upgrade事件,优先判断请求路径:如果是Next.js热重载专用的/_next/webpack-hmr路径,不做任何处理,Next.js内部逻辑会自动完成升级和后续热重载通信 - 非热重载路径的升级请求,调用
wss.handleUpgrade手动完成升级,触发自定义的connection事件处理业务逻辑 - 该方案对生产环境无影响,生产环境不存在热重载相关的WebSocket请求,所有符合规则的WebSocket请求都会走自定义逻辑,和原有生产环境的运行逻辑完全一致
内容的提问来源于stack exchange,提问作者Billy Moon
相关产品推荐
相关产品推荐

