如何在开发模式下在下一个 js 自定义服务器中运行 websocket 服务器
Posted
技术标签:
【中文标题】如何在开发模式下在下一个 js 自定义服务器中运行 websocket 服务器【英文标题】:How can I run a websocket server in next js custom server in dev mode 【发布时间】:2021-11-04 14:17:28 【问题描述】:假设我想运行一个自定义的下一个 js 服务器,并在同一台服务器上接受 websocket 连接,我怎样才能避免破坏下一个 js 开发服务器热重载,它也在同一台服务器上使用 websockets...
const createServer = require('http')
const WebSocket = require("ws")
const parse = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next( dev )
const handle = app.getRequestHandler()
app.prepare().then(() =>
const server = createServer((req, res) => handle(req, res, parse(req.url, true)))
// pass the same server instance that is used by next js to the websocket server
const wss = new WebSocket.Server( server )
wss.on("connection", async function connection(ws)
console.log('incoming connection', ws);
ws.onclose = () =>
console.log('connection closed', wss.clients.size);
;
);
server.listen(port, (err) =>
if (err) throw err
console.log(`> Ready on http://localhost:$port and ws://localhost:$port`)
)
)
我相信该服务器应该在生产构建版本中工作,以便在用于处理下一个 js 请求的同一服务器实例上创建 websocket 服务器,但是当我尝试这样做时,热模块重新加载停止工作,并且错误出现在 chrome 开发工具控制台中,因为它期望由 webpack 处理的 websocket 连接现在由我的自定义 websocket 服务器处理。
我怎样才能以某种方式将开发服务器的 websocket 连接路由到 next 以及 webpack 和其他服务器到我自己的处理程序?
我知道我可以在另一个端口上运行我的 websocket 服务器,但我想在与下一个 js 相同的服务器实例和相同的端口上运行它。
【问题讨论】:
我知道您提到您希望在与 Next.js 相同的服务器实例和端口上运行 WS,如何使用 http-proxy 将您的自定义 WS 请求转发到您的 WS 服务器? @PsyGik 这意味着在它自己的端口上运行 WS 服务器,然后在另一个端口上运行 Next,然后在将它们联系在一起的第三个端口上运行 http-proxy?我期望它会起作用(不确定代理 WS 的细节),但我希望做一些更简单的事情,这样我就可以在一个端口上启动一台服务器。 您只需要 2 台服务器。 1. Next.js 在它自己的端口上。 2. WS 服务器在它自己的端口上。然后在 Next.js 自定义服务器中使用 http-proxy 之类的东西将您的 WS 请求转发到您的自定义 WS 服务器。 为了让 DX 更简单,您可以使用 npm-run-all 或类似的东西一次性启动所有服务.. 我实际上发现我可以从next.config.js
内启动 websocket 服务器,我知道这很奇怪,但是可以。我真的很想避免分配另一个端口
【参考方案1】:
所以诀窍是创建一个 noServer 属性设置为 true 的 websocket 服务器,然后监听服务器升级事件,并根据路径名,不做任何事情以允许下一个 js 做它的事情,或者传递请求到我们创建的 websocket 服务器...
const wss = new WebSocket.Server( noServer: true )
server.on('upgrade', function (req, socket, head)
const pathname = parse(req.url, true);
if (pathname !== '/_next/webpack-hmr')
wss.handleUpgrade(req, socket, head, function done(ws)
wss.emit('connection', ws, req);
);
);
...所有这些都像这样...
const createServer = require('http')
const WebSocket = require("ws")
const parse = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next( dev )
const handle = app.getRequestHandler()
app.prepare().then(() =>
const server = createServer((req, res) => handle(req, res, parse(req.url, true)))
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);
;
);
server.on('upgrade', function (req, socket, head)
const pathname = parse(req.url, true);
if (pathname !== '/_next/webpack-hmr')
wss.handleUpgrade(req, socket, head, function done(ws)
wss.emit('connection', ws, req);
);
);
server.listen(port, (err) =>
if (err) throw err
console.log(`> Ready on http://localhost:$port and ws://localhost:$port`)
)
)
【讨论】:
感谢 @PsyGik 帮助我找到这个解决方案【参考方案2】:这是我使用 api 路由而不是创建自定义服务器在 Next.js 上创建 webSocket 服务器的答案。
/pages/api/websocketserverinit.js:
import WebSocketServer from 'ws';
const SocketHandler = async (req, res) =>
if (res.socket.server.wss)
console.log('Socket is already running')
else
console.log('Socket is initializing')
const server = res.socket.server
const wss = new WebSocketServer( noServer: true )
res.socket.server.wss = wss
server.on('upgrade', (req, socket, head) =>
console.log("upgrade", req.url)
if (!req.url.includes('/_next/webpack-hmr'))
wss.handleUpgrade(req, socket, head, (ws) =>
wss.emit('connection', ws, req);
);
);
wss.on('connection', (ws)=>
console.log("connection", ws);
ws.on('message', (data) =>
console.log('received: %s', data);
)
ws.send('something');
);
res.end()
export default SocketHandler
您必须调用 api 路由才能从客户端(或服务器初始化脚本)启动 websocket 服务器:
fetch("http://localhost:3000/api/websocketserverinit")
然后连接到它:
const ws = new WebSocket("ws://localhost:3000")
不是很好,但在某些情况下可能有用
【讨论】:
以上是关于如何在开发模式下在下一个 js 自定义服务器中运行 websocket 服务器的主要内容,如果未能解决你的问题,请参考以下文章
如何使用像filezilla这样的ftp服务器将没有vercel的下一个js应用程序部署到自定义服务器
使用JSP+Servlet+JavaBean的模式开发一个Web程序,将表单提交的数据显示在下一页面中。