如何使用Express.js正确地设置WebSocket服务器?

huangapple go评论60阅读模式
英文:

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()

huangapple
  • 本文由 发表于 2023年5月7日 23:19:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76194756.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定