英文:
How to set up a WebSocket server with Express.js (properly)?
问题
Please let me know if this is a duplicate.
请告诉我这是否是一个重复问题。
Description
描述:
I'll try to be concise. I have a barebones Express API with a WebSocket endpoint that I set up with express-ws
following the docs, but it doesn't work. I can't tell where the problem lies—client-side or server-side.
我会尽量简明扼要。我有一个基本的Express API,其中包含一个WebSocket端点,我按照文档使用express-ws
设置,但它不起作用。我无法确定问题出在哪里——是在客户端还是服务器端。
What I can tell is that FF (v112.0b6 dev ed) does not/cannot connect to my WebSocket endpoint.
我能告诉您的是FF(v112.0b6 dev ed)无法连接到我的WebSocket端点。
Server
服务器:
Dir structure
目录结构:
src/
api/
index.ts
app.ts
index.ts
src/index.ts
import app from './app';
const port = process.env.PORT || 80
app.listen(port, () => {
console.log(`Listening on http://localhost:${port}`)
})
src/app.ts
import express from 'express'
import api from './api'
const app = express()
app.use('/api/v1', api)
export default app
src/api/index.ts
import express from 'express' // v4.18.1
import expressWs from 'express-ws' // v5.0.2
expressWs(express())
const router = express.Router()
router.ws('/', (ws, req) => {
ws.on('message', msg => {
console.log(msg)
})
})
export default router
Server console
服务器控制台:
Listening on http://localhost:41240
BTW, other HTTP routers work fine on this app.
Client
客户端:
Browser console
浏览器控制台:
const socket = new WebSocket('ws://localhost:41240/api/v1')
socket.addEventListener('open', () => {
socket.send('iloveyou')
})
The browser console is open on http://localhost:41240
(same host).
Result
结果:
Browser console
浏览器控制台:
Firefox can’t establish a connection to the server at ws://localhost:41240/api/v1.
Sensibly, the client-side code does not execute further than the declaration of the socket, since that's where the connection fails.
Thank you for any help and do let me know if you need additional details.
明智的是,客户端代码不会执行比套接字声明更多的内容,因为连接失败就发生在那里。
感谢您提供的帮助,请告诉我是否需要额外的详细信息。
英文:
Please let me know if this is a duplicate.
Description
I'll try to be concise. I have a barebones Express API with a WebSocket endpoint that I set up with express-ws
following the docs, but it doesn't work. I can't tell where the problem lies—client-side or server-side.
What I can tell is that FF (v112.0b6 dev ed) does not/cannot connect to my WebSocket endpoint.
Server
Dir structure
src/
api/
index.ts
app.ts
index.ts
src/index.ts
import app from './app'
const port = process.env.PORT || 80
app.listen(port, () => {
console.log(`Listening on http://localhost:${port}`)
})
src/app.ts
import express from 'express'
import api from './api'
const app = express()
app.use('/api/v1', api)
export default app
src/api/index.ts
import express from 'express' // v4.18.1
import expressWs from 'express-ws' // v5.0.2
expressWs(express())
const router = express.Router()
router.ws('/', (ws, req) => {
ws.on('message', msg => {
console.log(msg)
})
})
export default router
Server console
Listening on http://localhost:41240
BTW, other HTTP routers work fine on this app.
Client
Browser console
const socket = new WebSocket('ws://localhost:41240/api/v1')
socket.addEventListener('open', () => {
socket.send('iloveyou')
})
The browser console is open on http://localhost:41240
(same host).
Result
Browser console
Firefox can’t establish a connection to the server at ws://localhost:41240/api/v1.
Sensibly, the client-side code does not execute further than the declaration of the socket, since that's where the connection fails.
Thank you for any help and do let me know if you need additional details.
答案1
得分: 1
/src/api/index.ts
文件中这行代码有问题:
expressWs(express())
这样会创建一个新的 app
对象,而不是连接到你正在运行的 HTTP 服务器上。这个 app
需要是你应用程序其他部分正在使用的相同 app
对象,而不是一个新的对象。可能导入此模块的人需要在某个初始化函数中传递 app
对象,然后可以使用共享的 app
对象初始化 expressWs
。
在这个 expressWs 文档示例 中,你可以看到只有一个 app
对象,express 和 expressWs 都在使用,而且 expressWs 需要能够连接到你现有的 Web 服务器。
英文:
This line of /src/api/index.ts
:
expressWs(express())
is not correct. That is creating a new app
object that is not connected to your running http server. That app
needs to be the SAME app
object that the rest of your app is using, not a new one. Probably whoever imports this module needs to pass it the app
object in some initialization function and you can then initialize expressWs
using the shared app
object.
In this expressWs doc example, you can see that there's only one app
object that both express and expressWs are using, plus it makes sense that expressWs needs to be able to hook into your existing web server.
答案2
得分: 1
这个评论内容太多了,所以我会将其作为答案发布,以展示我最终用作解决方案的内容。
描述
我将app
对象隔离到一个文件中,并对其进行了导出。在src/api/index.ts
中导入了这个app
,然后将其传递给expressWs
进行初始化。稍后在该文件中,我定义了一个router.ws
,并导出了这个路由(在src/app.ts
中导入了一级)。
在src/app.ts
中,我也导入了app
对象以及src/api/index.ts
的路由。其余的代码保留与问题描述中相同。
WebSocket连接现在正常工作,并可以传输数据。
服务器
新目录结构
src/
api/
index.ts
lib/
app/
index.ts
app.ts
index.ts
更新的src/app.ts
import { app } from '#lib/app'
import api from './api'
app.use('/api/v1', api)
export default app
更新的src/api/index.ts
import { app } from '#lib/app'
import express from 'express'
import expressWs from 'express-ws'
expressWs(app)
const router = express.Router()
router.ws('/', (ws, req) => {
ws.on('message', msg => {
console.log(msg)
})
})
export default router
新的src/lib/app/index.ts
import express from 'express'
export const app = express()
英文:
This comment would be too much for a comment, so I'll post it as an answer, to show what I've finally used as my solution.
Description
I isolated the app
object to a file, which exports it. This app
is imported in src/api/index.ts
, where it is passed to expressWs
for initialisation. Later in that file, I define a router.ws
and I export this router (it's imported one level up in src/app.ts
).
In src/app.ts
, I import the app
object as well, and src/api/index.ts
's router. The rest of the code is left as in the question description.
The WebSocket connection now works properly and can transmit data.
Server
New dir structure
src/
api/
index.ts
lib/
app/
index.ts
app.ts
index.ts
Updated src/app.ts
import { app } from '#lib/app'
import api from './api'
app.use('/api/v1', api)
export default app
Updated src/api/index.ts
import { app } from '#lib/app'
import express from 'express'
import expressWs from 'express-ws'
expressWs(app)
const router = express.Router()
router.ws('/', (ws, req) => {
ws.on('message', msg => {
console.log(msg)
})
})
export default router
New src/lib/app/index.ts
import express from 'express'
export const app = express()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论