Socket.io客户端:用一个处理程序响应所有事件?


82

是否有可能让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代码收到任何/所有事件时调用此回调函数。

这可能吗?怎么样?


我在转发所有事件类型时打开了以下问题,我也一直在添加发现的解决方案:github.com/Automattic/socket.io/issues/1715
Peter Uithoven 2014年

Answers:


25

看起来socket.io库将它们存储在字典中。因此,不要修改源代码就不可能做到这一点。

来自来源

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;
  };


在2019年,我认为情况不再如此。
乌斯奎尔rel

82

更新了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之一离我很近,但没有一个答案对我有用,这是我调整后的版本。

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


2
谢谢,这帮助我调试了丢失的事件!
弥勒

1
不幸的是不能使用'user。*';之类的东西。也许我可以设法实现它。
C4d

嗨,非常好,但是如果您可以提供一些输出示例,这可能会有所帮助^^我觉得我需要运行代码才能理解您的答案:)
538ROMEO

24

最后,有一个名为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);

11

干得好 ...

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版本:0.9.10,开发。
2012年

3
最终发布吗?
hacklikecrack

9

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

您可以覆盖套接字。

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

  • 陷阱所有事件
  • 仅捕获未被旧方法捕获的事件(它是默认侦听器)
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));
});

致电之前有关aync操作的任何建议均适用。setTimeout(function(){original_ $ emit.apply(socket,['*']。concat(args)); if(!original_ $ emit.apply(socket,arguments)){original_ $ emit.apply(socket,[ 'default']。concat(args));}},2000年);
恩基2014年

我正在使用Socket.IO 1.3.6,似乎不再有$ emit方法socket
raimohanska 2015年

确实。检查@Flion 1.x版本的答案
leszek.hanusz

7

当前(2013年4月)有关公开事件的GitHub文档提到了socket.on('anything')。看起来“任何东西”都是自定义事件名称的占位符,而不是捕获任何事件的实际关键字。

我刚刚开始使用Web套接字和Node.JS,并且立即需要处理任何事件以及发现发送了什么事件。不能完全相信socket.io中缺少此功能。


5

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

参考文献:


3

关于这个话题进行了长时间讨论在Socket.IO库发行回事。此处张贴了各种解决方案(例如,用EventEmitter2覆盖EventEmitter)。几个星期前,lmjabreu发布了另一个解决方案:一个名为socket.io-wildcard的npm模块,该模块在通配符事件中修补到Socket.IO(与当前的Socket.IO兼容,约为0.9.14)。


4
但这仅是服务器端...他的模块无法在客户端(浏览器)上使用
Sander 2014年

3

因为您的问题在寻求解决方案时很笼统,所以我将提出一个不需要修改代码的问题,只需要更改套接字的使用方式即可。

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

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

在服务器上,类似...

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

我不知道是否总是使用相同的事件可能会导致任何问题,也许会发生大规模的冲突,但这很好地达到了我的目的。


1

我发现的所有方法(包括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)...


我可以确认它是有效的,并且正如您所观察到的,它是唯一起作用的(在某种意义上:对我来说也是)。非常感谢你!
2015年

1

@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
};

1

即使这是一个老问题,我也有同样的问题,并使用了本地套接字解决了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');
})

0

我正在使用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}]`);
  }
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.