如何检测从 Websocket 服务器发送的消息
Posted
技术标签:
【中文标题】如何检测从 Websocket 服务器发送的消息【英文标题】:How to detect which message was sent from the Websocket server 【发布时间】:2020-11-09 09:31:22 【问题描述】:我有一个小型 Web 应用程序正在侦听来自 Websocket 服务器的传入消息。我是这样收到的
const webSocket = new WebSocket("wss://echo.websocket.org");
webSocket.onopen = event => webSocket.send("test");
webSocket.onmessage = event => console.log(event.data);
但发送服务器更复杂。可能会出现多种类型的消息,例如“UserConnected”、“TaskDeleted”、“ChannelMoved”
如何检测发送的消息类型?现在我将代码修改为
const webSocket = new WebSocket("wss://echo.websocket.org");
webSocket.onopen = event =>
const objectToSend = JSON.stringify(
message: "test-message",
data: "test"
);
webSocket.send(objectToSend);
;
webSocket.onmessage = event =>
const objectToRead = JSON.parse(event.data);
if (objectToRead.message === "test-message")
console.log(objectToRead.data);
;
所以我必须从服务器发送一个包含“方法名称”/“消息类型”的对象,例如“TaskDeleted”识别在客户端执行的正确方法?那会导致一个很大的 switch case 语句,不是吗?
有没有更好的方法?
【问题讨论】:
你会更容易使用一些帮助库,如 (socket.io) 它会解决你的问题yt tutorial 是的,这是个好主意。但是如果服务器没有socket.io,那需要发送哪种消息格式呢?这样socket.io仍然能够解析消息 【参考方案1】:您可以通过直接映射方法来避免大的 switch-case 语句:
// List of white-listed methods to avoid any funny business
let allowedMethods = ["test", "taskDeleted"];
function methodHandlers()
this.test = function(data)
console.log('test was called', data);
this.taskDeleted = function(data)
console.log('taskDeleted was called', data);
webSocket.onmessage = event =>
const objectToRead = JSON.parse(event.data);
let methodName = objectToRead.message;
if (allowerMethods.indexOf(methodName)>=0)
let handler = new methodHandlers();
handler[methodName](data);
else
console.error("Method not allowed: ", methodName)
;
【讨论】:
非常感谢您的代码。我更喜欢类似于 socket.io 的解决方案。socket.on(eventName, callback)
但问题是我不知道服务器需要发送的格式以从中解析 eventName【参考方案2】:
根据 Eriks Klotins 的回答,我想提供一个我目前正在使用的解决方案。但是有必要定义一个消息格式。我想过这种格式
"event": "event name goes here",
"data":
"arg1": "first argument"
基于此我将代码修改为
const webSocket = new WebSocket("wss://echo.websocket.org");
webSocket.onopen = event =>
const objectToSend = JSON.stringify(
event: "test",
data:
argOne: "argument 1"
);
webSocket.send(objectToSend);
;
webSocket.onmessage = event =>
const objectToRead = JSON.parse(event.data);
const eventMethods = events();
const eventMethod = eventMethods[objectToRead.event];
eventMethod(objectToRead.data);
;
function events()
return
test: function( argOne )
console.log(argOne);
;
【讨论】:
【参考方案3】:正如您在其中一个 cmets 中要求的那样,为像 socket.io 这样的 websockets 提供一个流畅的接口。
您可以使用简单的 PubSub(发布订阅)设计模式使其流畅,这样您就可以订阅特定的消息类型。 Node 提供了 EventEmitter 类,因此您可以继承 on
和 emit
事件,但是,在此示例中是使用类似 API 的快速模型。
在生产环境中,我建议在 node.js 环境中使用本机 EventEmitter,并在前端使用与浏览器兼容的 npm 包。
查看每件作品的描述。
订阅者保存在一个带有一组回调的简单对象中,如果需要,您可以添加取消订阅。
注意:如果你使用的是 node.js,你可以扩展 EventEmitter
// This uses a similar API to node's EventEmitter, you could get it from a node or a number of browser compatible npm packages.
class EventEmitter
// [event: string]: Set<(data: any) => void>
__subscribers =
// subscribe to specific message types
on(type, cb)
if (!this.__subscribers[type])
this.__subscribers[type] = new Set
this.__subscribers[type].add(cb)
// emit a subscribed callback
emit(type, data)
if (typeof this.__subscribers[type] !== 'undefined')
const callbacks = [...this.__subscribers[type]]
callbacks.forEach(cb => cb(data))
class SocketYO extends EventEmitter
constructor( host )
super()
// initialize the socket
this.webSocket = new WebSocket(host);
this.webSocket.onopen = () =>
this.connected = true
this.emit('connect', this)
this.webSocket.onerror = console.error.bind(console, 'SockyError')
this.webSocket.onmessage = this.__onmessage
// send a json message to the socket
send(type, data)
this.webSocket.send(JSON.stringify(
type,
data
))
on(type, cb)
// if the socket is already connected immediately call the callback
if (type === 'connect' && this.connected)
return cb(this)
// proxy EventEmitters `on` method
return super.on(type, cb)
// catch any message from the socket and call the appropriate callback
__onmessage = e =>
const type, data = JSON.parse(e.data)
this.emit(type, data)
// create your SocketYO instance
const socket = new SocketYO(
host: 'wss://echo.websocket.org'
)
socket.on('connect', (socket) =>
// you can only send messages once the socket has been connected
socket.send('myEvent',
message: 'hello'
)
)
// you can subscribe without the socket being connected
socket.on('myEvent', (data) =>
console.log('myEvent', data)
)
【讨论】:
以上是关于如何检测从 Websocket 服务器发送的消息的主要内容,如果未能解决你的问题,请参考以下文章