Клиент Socket.io: отвечать на все события одним обработчиком?
Возможно ли, чтобы клиент 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 на стороне клиента.
Возможно ли это? Как?
Ответы
Ответ 1
Похоже, что библиотека 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;
};
Ответ 2
Обновленное решение для 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);
});
Ни один из ответов не работал у меня, хотя один из Матиаса Хопфа и Марос Пиксель приблизился, это моя скорректированная версия.
ПРИМЕЧАНИЕ., это только улавливает пользовательские события, а не подключается/отключается и т.д.
Ответ 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);
Ответ 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));
});
Это будет захватывать события, такие как connecting
, connect
, disconnect
, reconnecting
, поэтому будьте осторожны.
Ответ 5
Примечание: этот ответ действителен только для socket.io 0.x
Вы можете переопределить сокет . $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));
});
Ответ 6
В текущем (апрель 2013 г.) документе GitHub для открытых событий упоминается socket.on('anything')
. Похоже, что "все" является заполнителем для имени настраиваемого события, а не фактическим ключевым словом, которое могло бы поймать любое событие.
Я только начал работать с веб-сокетами и Node.JS и сразу же нуждался в обработке любого события, а также для выяснения того, какие события были отправлены. Не могу поверить, что эта функция отсутствует в socket.io.
Ответ 7
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)
}
})
Ссылки:
Ответ 8
продолжительное обсуждение этого вопроса продолжается на странице проблемы репозитория Socket.IO. Существует множество решений, размещенных там (например, переопределение EventEmitter с EventEmitter2). lmjabreu выпустила еще одно решение пару недель назад: модуль npm под названием socket.io-wildcard, который патнет в подстановочном событии на Socket.IO(работает с текущим Socket.IO, ~ 0.9.14).
Ответ 9
Поскольку ваш вопрос был довольно общим в просьбе о решении, я поставлю его, который не требует взлома кода, просто изменение в том, как вы используете сокет.
Я просто решил, что мое клиентское приложение отправит то же самое событие, но с другой полезной нагрузкой.
socket.emit("ev", { "name" : "miscEvent1"} );
socket.emit("ev", { "name" : "miscEvent2"} );
А на сервере что-то вроде...
socket.on("ev", function(eventPayload) {
myGenericHandler(eventPayload.name);
});
Я не знаю, может ли всегда использовать одно и то же событие, может вызвать какие-либо проблемы, может быть, какие-то столкновения в масштабе, но это очень помогло моим целям.
Ответ 10
Все методы, которые я нашел (включая 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
};
Это может быть и решение для других. Тем не менее, в банкомате я точно не понимаю, почему у кого-то еще нет проблем с существующими "решениями"?!? Есть идеи? Может быть, это моя старая версия node (0.10.31)...
Ответ 11
@Ответ Маттиаса Хопфа
Обновлен ответ для 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
};
Ответ 12
Я использую 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}]');
}
});