Клиент Socket.io: отвечать на все события одним обработчиком?


83

Возможно ли, чтобы клиент 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
Питер Уитховен

Ответы:


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 году я больше не думаю, что это так.
Urasquirrel 09

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

Ни один из ответов не сработал для меня, хотя ответ Матиаса Хопфа и Мароса Пикселя был близок, это моя скорректированная версия.

ПРИМЕЧАНИЕ: это фиксирует только пользовательские события, а не подключение / отключение и т. Д.


2
Спасибо, это помогло мне отладить пропущенные события!
Майтрейя

1
К сожалению, не работает с такими вещами, как 'user. *' ;. Может, мне удастся это реализовать.
C4d

Привет, очень хорошо, но было бы полезно, если бы у вас были примеры вывода ^^ Я чувствую, что мне нужно запустить код, чтобы понять ваш ответ :)
grobouDu06 03

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

Это позволит отлавливать события , как connecting, connect, disconnect, reconnectingтоже, так что не все равно берут.


Socket.IO.js сборка: 0.9.10, разработка.
Каустубх Каркаре,

3
Это закончилось релизом?
hacklikecrack

9

Примечание: этот ответ действителен только для 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));
});

Любые советы по операции aync перед вызовом применяются. setTimeout (function () {original_ $ emit.apply (socket, ['*']. concat (args)); if (! original_ $ emit.apply (socket, arguments)) {original_ $ emit.apply (socket, [ 'default']. concat (args));}}, 2000);
Enki

Я использую Socket.IO 1.3.6, и похоже, что в нем socketбольше нет метода $
emit

Конечно. Проверьте ответ @Flion для версий 1.x
leszek.hanusz

7

В текущем (апрель 2013 г.) документе GitHub по раскрытым событиям упоминается файл socket.on('anything'). Похоже, что «что-нибудь» является заполнителем для имени настраиваемого события, а не фактическим ключевым словом, которое могло бы уловить любое событие.

Я только начал работать с веб-сокетами и Node.JS, и мне сразу понадобилось обработать любое событие, а также выяснить, какие события были отправлены. Не могу поверить, что эта функция отсутствует в socket.io.


5

socket.io-client 1.7.3

По состоянию на май 2017 года ни одно из других решений не могло работать так, как я хотел - сделал перехватчик, использующий в 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 ведется долгое обсуждение этой темы . Там опубликовано множество решений (например, переопределение EventEmitter с помощью EventEmitter2). Пару недель назад lmjabreu выпустил другое решение: модуль npm под названием socket.io-wildcard, который исправляет событие подстановочного знака в Socket.IO (работает с текущим Socket.IO, ~ 0.9.14).


4
Но это только на стороне сервера ... его модуль не может использоваться на стороне клиента (в браузере)
Сандер

3

Поскольку ваш вопрос был довольно общим, предлагая решение, я предлагаю тот, который не требует взлома кода, просто изменение того, как вы используете сокет.

Я просто решил, что мое клиентское приложение будет отправлять точно такое же событие, но с другой полезной нагрузкой.

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

А на сервере что-то вроде ...

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

Я не знаю, может ли постоянное использование одного и того же события вызвать какие-либо проблемы, возможно, столкновения какого-то масштаба, но это отлично послужило моим целям.


2

Несмотря на то, что это старый вопрос, у меня та же проблема, и я решил ее с помощью собственного сокета, в 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');
})

1

Все найденные мной методы (включая socket.io-wildcard и socketio-wildcard) у меня не работали. Видимо в socket.io 1.3.5 нет $ emit ...

После прочтения кода socket.io я исправил следующее, что ДЕЙСТВИТЕЛЬНО работает:

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

Это может быть решением и для других. Тем не менее, банкомат. Я не совсем понимаю, почему, похоже, ни у кого нет проблем с существующими «решениями»?!? Есть идеи? Может, это моя старая версия узла (0.10.31) ...


Я могу подтвердить, что он работает, и, как вы заметили, это единственный, который работает (в том смысле, что и для меня). Большое спасибо!
отметка

1

@Matthias Hopf ответ

Обновленный ответ для v1.3.5. Была ошибка с аргументами, если вы хотите слушать старое событие и *событие вместе.

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

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}]`);
  }
});

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.