我有一个小型的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语句,不是吗?
还有更好的方法吗?
答案 0 :(得分: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)
}
};
答案 1 :(得分:1)
基于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);
}
};
}
答案 2 :(得分:0)
正如您在评论之一中所要求的那样,为websockets(例如socket.io)提供一个流畅的界面。
您可以使用简单的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)
})