如何检测从Websocket服务器发送的消息

时间:2020-11-09 09:31:22

标签: javascript websocket

我有一个小型的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语句,不是吗?

还有更好的方法吗?

3 个答案:

答案 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类,因此您可以继承onemit事件,但是,在此示例中,它是使用类似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)
})