【问题标题】:Socket.io Client: respond to all events with one handler?Socket.io 客户端:用一个处理程序响应所有事件?
【发布时间】:2012-05-11 09:57:45
【问题描述】:

是否可以让 socket.io 客户端响应所有事件而无需单独指定每个事件?

例如,像这样的东西(现在显然行不通):

var socket = io.connect("http://myserver");

socket.on("*", function(){
  // listen to any and all events that are emitted from the
  // socket.io back-end server, and handle them here.

  // is this possible? how can i do this?
});

我希望在客户端 socket.io 代码收到任何/所有事件时调用此回调函数。

这可能吗?怎么样?

【问题讨论】:

标签: javascript events socket.io


【解决方案1】:

socket.io-client 1.3.7

的更新解决方案
var onevent = socket.onevent;
socket.onevent = function (packet) {
    var args = packet.data || [];
    onevent.call (this, packet);    // original call
    packet.data = ["*"].concat(args);
    onevent.call(this, packet);      // additional call to catch-all
};

这样使用:

socket.on("*",function(event,data) {
    console.log(event);
    console.log(data);
});

没有一个答案对我有用,虽然 Mathias Hopf 和 Maros Pixel 的答案很接近,但这是我调整后的版本。

注意:这只会捕获自定义事件,而不是连接/断开连接等

【讨论】:

  • 谢谢,这帮助我调试了丢失的事件!
  • 不幸的是不能使用像'user.*'这样的东西;。也许我可以设法实现它。
  • 您好,非常好,但如果您有一些输出示例可能会有所帮助^^ 我觉得我需要运行代码才能理解您的答案:)
【解决方案2】:

看起来 socket.io 库将这些存储在字典中。因此,不要认为如果不修改源代码就可以做到这一点。

来自source

EventEmitter.prototype.on = function (name, fn) {
    if (!this.$events) {
      this.$events = {};
    }

    if (!this.$events[name]) {
      this.$events[name] = fn;
    } else if (io.util.isArray(this.$events[name])) {
      this.$events[name].push(fn);
    } else {
      this.$events[name] = [this.$events[name], fn];
    }

    return this;
  };

【讨论】:

【解决方案3】:

最后,有一个名为socket.io-wildcard 的模块允许在客户端和服务器端使用通配符

var io         = require('socket.io')();
var middleware = require('socketio-wildcard')();

io.use(middleware);

io.on('connection', function(socket) {
  socket.on('*', function(){ /* … */ });
});

io.listen(8000);

【讨论】:

  • 回调是否可能仅在disconnect 上不触发?
【解决方案4】:

给你...

var socket = io.connect();
var globalEvent = "*";
socket.$emit = function (name) {
    if(!this.$events) return false;
    for(var i=0;i<2;++i){
        if(i==0 && name==globalEvent) continue;
        var args = Array.prototype.slice.call(arguments, 1-i);
        var handler = this.$events[i==0?name:globalEvent];
        if(!handler) handler = [];
        if ('function' == typeof handler) handler.apply(this, args);
        else if (io.util.isArray(handler)) {
            var listeners = handler.slice();
            for (var i=0, l=listeners.length; i<l; i++)
                listeners[i].apply(this, args);
        } else return false;
    }
    return true;
};
socket.on(globalEvent,function(event){
    var args = Array.prototype.slice.call(arguments, 1);
    console.log("Global Event = "+event+"; Arguments = "+JSON.stringify(args));
});

这也会捕获connectingconnectdisconnectreconnecting 之类的事件,所以请小心。

【讨论】:

  • Socket.IO.js build:0.9.10,开发。
  • 最终发布了吗?
【解决方案5】:

注意:此答案仅对 socket.io 0.x 有效

您可以覆盖 socket.$emit

使用以下代码,您有两个新功能:

  • 捕获所有事件
  • 仅捕获旧方法未捕获的事件(它是默认侦听器)
var original_$emit = socket.$emit;
socket.$emit = function() {
    var args = Array.prototype.slice.call(arguments);
    original_$emit.apply(socket, ['*'].concat(args));
    if(!original_$emit.apply(socket, arguments)) {
        original_$emit.apply(socket, ['default'].concat(args));
    }
}

socket.on('default',function(event, data) {
    console.log('Event not trapped: ' + event + ' - data:' + JSON.stringify(data));
});

socket.on('*',function(event, data) {
    console.log('Event received: ' + event + ' - data:' + JSON.stringify(data));
});

【讨论】:

  • 在调用 apply 之前关于 aync 操作的任何建议。 setTimeout(function() { original_$emit.apply(socket, ['*'].concat(args)); if(!original_$emit.apply(socket, arguments)) { original_$emit.apply(socket, [ '默认'].concat(args)); } }, 2000);
  • 我正在使用 Socket.IO 1.3.6,socket 中似乎没有 $emit 方法
  • 确实如此。检查@Flion 1.x 版本的答案
【解决方案6】:

当前(2013 年 4 月)GitHub doc on exposed events 提到了 socket.on('anything')。 'anything' 似乎是自定义事件名称的占位符,而不是可以捕获任何事件的实际关键字。

我刚刚开始使用 Web 套接字和 Node.JS,并且立即需要处理任何事件,以及发现发送了哪些事件。不敢相信 socket.io 缺少这个功能。

【讨论】:

    【解决方案7】:

    正如v3.0 documentation

    socket.onAny((event, ...args) => {
      console.log(`got ${event}`);
    });
    

    【讨论】:

      【解决方案8】:

      socket.io-client 1.7.3

      截至 2017 年 5 月,无法让任何其他解决方案完全按照我的意愿工作 - 制作了一个拦截器,仅在 Node.js 上用于测试目的:

      var socket1 = require('socket.io-client')(socketUrl)
      socket1.on('connect', function () {
        console.log('socket1 did connect!')
        var oldOnevent = socket1.onevent
        socket1.onevent = function (packet) {
          if (packet.data) {
            console.log('>>>', {name: packet.data[0], payload: packet.data[1]})
          }
          oldOnevent.apply(socket1, arguments)
        }
      })
      

      参考资料:

      【讨论】:

        【解决方案9】:

        因为您的问题在寻求解决方案时非常笼统,所以我将介绍这个不需要破解代码的问题,只需改变您使用套接字的方式即可。

        我刚刚决定让我的客户端应用发送完全相同的事件,但使用不同的有效负载。

        socket.emit("ev", { "name" : "miscEvent1"} );
        socket.emit("ev", { "name" : "miscEvent2"} );
        

        在服务器上,类似...

        socket.on("ev", function(eventPayload) {
           myGenericHandler(eventPayload.name);
        });
        

        我不知道是否总是使用相同的事件会导致任何问题,可能是某种规模的冲突,但这正好符合我的目的。

        【讨论】:

          【解决方案10】:

          在 Socket.IO 存储库问题页面上有 a long discussion about this topic。那里发布了各种解决方案(例如,用 EventEmitter2 覆盖 EventEmitter)。 lmjabreu 几周前发布了另一个解决方案:一个名为 socket.io-wildcard 的 npm 模块,该模块将通配符事件修补到 Socket.IO(适用于当前的 Socket.IO,~0.9.14)。

          【讨论】:

          • 但这只是服务器端......他的模块在客户端(浏览器)上不可用
          【解决方案11】:

          尽管这是一个老问题,但我也遇到了同样的问题,并使用Node.js 中的本机套接字解决了这个问题,它有一个 .on('data') 事件,每次数据到来时都会触发。所以这就是我到目前为止所做的:

          const net = require('net')
          
          const server = net.createServer((socket) => {
              // 'connection' listener.
              console.log('client connected')
          
              // The stuff I was looking for
              socket.on('data', (data) => {
                  console.log(data.toString())
              })
          
              socket.on('end', () => {
                  console.log('client disconnected')
              })
          })
          
          server.on('error', (err) => {
              throw err;
          })
          
          server.listen(8124, () => {
              console.log('server bound');
          })
          

          【讨论】:

            【解决方案12】:

            我发现的所有方法(包括 socket.io-wildcard 和 socketio-wildcard)都不适合我。显然 socket.io 1.3.5 中没有 $emit ...

            阅读 socket.io 代码后,我修补了以下 DID 工作:

            var Emitter = require('events').EventEmitter;
            var emit = Emitter.prototype.emit;
            [...]
            var onevent = socket.onevent;
            socket.onevent = function (packet) {
                var args = ["*"].concat (packet.data || []);
                onevent.call (this, packet);    // original call
                emit.apply   (this, args);      // additional call to catch-all
            };
            

            这也可能是其他人的解决方案。但是,ATM 我不完全理解为什么其他人似乎对现有的“解决方案”有问题?!?有任何想法吗?也许是我的旧节点版本(0.10.31)...

            【讨论】:

            • 我可以确认它有效,并且正如您所观察到的,它是唯一有效的(从某种意义上说:对我来说也是如此)。非常感谢!
            【解决方案13】:

            @Matthias Hopf 回答

            更新了 v1.3.5 的答案。如果您想同时收听旧事件和 * 事件,则 args 存在错误。

            var Emitter = require('events').EventEmitter;
            var emit = Emitter.prototype.emit;
            // [...]
            var onevent = socket.onevent;
            socket.onevent = function (packet) {
                var args = packet.data || [];
                onevent.call (this, packet);    // original call
                emit.apply   (this, ["*"].concat(args));      // additional call to catch-all
            };
            

            【讨论】:

              【解决方案14】:

              我正在使用 Angular 6 和 npm 包:ngx-socket-io

              import { Socket } from "ngx-socket-io";
              

              ...

              constructor(private socket: Socket) { }
              

              ...

              连接套接字后,我使用这段代码,这是处理所有自定义事件...

              const onevent = this.socket.ioSocket.onevent;
              this.socket.ioSocket.onevent = function (packet: any) {
                const args = packet.data || [];
                onevent.call(this, packet);    // original call
                packet.data = ["*"].concat(args);
                onevent.call(this, packet);      // additional call to catch-all
              };
              this.socket.on("*", (eventName: string, data: any) => {
                if (typeof data === 'object') {
                  console.log(`socket.io event: [${eventName}] -> data: [${JSON.stringify(data)}]`);
                } else {
                  console.log(`socket.io event: [${eventName}] -> data: [${data}]`);
                }
              });
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2021-03-05
                • 2017-05-18
                • 2016-08-09
                • 2015-04-30
                • 1970-01-01
                • 2020-12-16
                • 2011-03-18
                相关资源
                最近更新 更多