在Node.js的Express中使用ws库是否需导入http的createServer?
你的结论不完全准确,但必须获取标准HTTP服务器实例才能让WebSocketServer与Express配合工作,显式导入createServer是可行方式之一,但不是唯一途径。
为什么第一段代码无法运行?
Express的app对象本质是一个请求处理中间件函数,并非标准的HTTP服务器实例。而ws库的WebSocketServer要求传入的server选项必须是Node.js原生http.Server(或https.Server)实例——它需要基于这个服务器来升级HTTP连接为WebSocket连接。
第一段代码中,你直接把app传给了WebSocketServer,但app不具备HTTP服务器的相关接口,导致WebSocketServer无法正确绑定和监听连接。另外,app.listen()内部确实会调用http.createServer(app)创建服务器,但你是先创建wss再调用app.listen(),此时app还没有关联到任何HTTP服务器实例,所以wss初始化失败。
可行的两种写法
1. 显式创建HTTP服务器(你使用的第二种代码)
通过import { createServer } from 'http'显式创建服务器实例,把Express的app作为请求处理函数传入,再将这个服务器实例传给WebSocketServer,这是最清晰直观的写法。
代码示例:
import { createServer } from 'http'; import express from "express"; import { WebSocketServer } from 'ws'; const app = express(); const port = 80; const server = createServer(app) const wss = new WebSocketServer({ server:server }); wss.on('connection', function connection(ws) { ws.on('message', function message(data) { console.log('received: %s', data); }); }); server.listen(port, function () { console.log("Server listening on port: " + port); });
2. 通过app.listen()的返回值获取服务器实例
app.listen()方法内部会创建HTTP服务器并启动监听,同时返回这个服务器实例。所以可以先调用app.listen()拿到服务器,再传给WebSocketServer,这种方式不需要显式导入createServer:
代码示例:
import express from "express"; import { WebSocketServer } from 'ws'; const app = express(); const port = 80; // 先启动Express服务器,获取返回的HTTP服务器实例 const server = app.listen(port, function () { console.log("Server listening on port: " + port); }); // 用服务器实例创建WebSocketServer const wss = new WebSocketServer({ server: server }); wss.on('connection', function connection(ws) { ws.on('message', function message(data) { console.log('received: %s', data); }); });
总结
- 核心要求是
WebSocketServer必须绑定到Node.js原生HTTP服务器实例,Express的app本身无法满足这个要求。 - 显式导入
createServer是可行方式,但不是必须的——通过app.listen()的返回值也能拿到所需的服务器实例。 - 你的结论“必须导入{ createServer } from 'http'”不够严谨,但获取HTTP服务器实例是必不可少的步骤。
内容的提问来源于stack exchange,提问作者Schwan Abdulkareem

