Express与Secure WebSocket(wss)端口冲突问题求助
解决Express与安全WebSocket(wss)共用同一端口的问题
核心问题分析
你代码里的关键错误是同时调用了server.listen()和app.listen(),这会启动两个完全独立的服务器:
server是带SSL证书的HTTPS服务器,同时承载wss服务app.listen()会创建一个新的无SSL的HTTP服务器
这两个服务器无法共用同一端口,直接导致了你遇到的“要么WebSocket失效、要么Express无响应”的冲突问题。
解决方案:仅启动HTTPS服务器
不需要双端口,完全可以共用同一端口。只需要移除app.listen(PORT)这一行,让承载了Express的HTTPS服务器来监听端口即可。因为你已经通过https.createServer({ key, cert }, app)把Express的请求处理逻辑绑定到了HTTPS服务器上,这个服务器会同时处理:
- 常规的HTTPS请求(对应Express的路由接口)
- WebSocket的升级请求(对应wss连接)
修正后的核心代码
const app = express() const server = https.createServer({ key, cert }, app); const wss = new WebSocket.Server({ server}) // 配置wss连接逻辑 wss.on('connection', (ws, req) => { console.log('received socket connection ', req.headers['sec-websocket-key']) // ... 你的其他wss处理代码 }) // 只启动HTTPS服务器,共用同一端口 const PORT = process.env.PORT || 3002 server.listen(PORT); console.log('Server is listening on port ' + PORT);
完整修正后的代码片段
const WebSocket = require('ws'); const fs = require('fs'); const https = require('https'); const express = require('express') require('dotenv').config() const keypath = process.env.environment=="production" ? process.env.key : 'localhost.key'; const certpath = process.env.environment=="production" ? process.env.cert : 'localhost.crt'; console.log("environment is ",process.env.environment) const key = fs.readFileSync(keypath); const cert = fs.readFileSync(certpath); const bodyParser = require('body-parser') const mongoose = require('mongoose') const cors = require('cors') const helmet = require('helmet') const morgan = require('morgan') const { MONGO_URI } = require('./config') const worldRoutes = require('./src/routes/api/world_controller') const environmentRoutes = require('./src/routes/api/environment_controller') const worldObjectRoutes = require('./src/routes/api/worldObject_controller') const interactionRoutes = require('./src/routes/api/interaction_controller') const baseRoutes = require('./src/routes/api/base_controller') // 补充baseRoutes的引入 const app = express() app.use(helmet()) app.use(bodyParser.json()) app.use(cors()) app.use(morgan(':method :url :status :res[content-length] - :response-time ms')) app.use(express.json()) mongoose .connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true, }) .then(() => console.log('MongoDB connected!')) .catch((err) => console.log(err)) app.use('/api/world', worldRoutes) app.use('/', baseRoutes) const PORT = process.env.PORT || 3002 const server = https.createServer({ key, cert }, app); const wss = new WebSocket.Server({ server}) wss.on('connection', (ws, req) => { console.log('received socket connection ', req.headers['sec-websocket-key']) // ... 你的其他wss处理代码 }) // 移除app.listen(PORT),只启动HTTPS服务器 server.listen(PORT); console.log('Server is listening on port ' + PORT); // 注:原代码里的upgrade事件监听不需要手动添加,ws库会自动处理
额外说明
- 你之前用非安全WebSocket(ws)时没问题,是因为当时应该是基于
http.createServer(app)启动的单服务器,没有额外调用app.listen(),所以HTTP和ws可以共用端口。 - 当使用wss时,必须依赖HTTPS服务器的SSL层,所以所有请求(包括Express接口和WebSocket连接)都要通过这个带证书的HTTPS服务器处理,不能再单独启动Express的HTTP服务器。
内容的提问来源于stack exchange,提问作者Daniel Shen
相关产品推荐
相关产品推荐

