Socket.io 客户端:使用一个处理程序响应所有事件
Socket.io Client: respond to all events with one handler?
是否可以让 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 代码收到任何/所有事件时调用此回调函数。
这可能吗?如何?
更新了 socket.io 客户端 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的答案很接近,这是我调整后的版本。
注意:这仅捕获自定义事件,而不捕获连接/断开连接等
看起来 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;
};
最后,有一个名为 socket.io 通配符的模块,它允许在客户端和服务器端使用通配符
var io = require('socket.io')();
var middleware = require('socketio-wildcard')();
io.use(middleware);
io.on('connection', function(socket) {
socket.on('*', function(){ /* … */ });
});
io.listen(8000);
你去...
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
这样的事件,所以要小心。
注意:此答案仅对 0.x socket.io 有效
您可以覆盖套接字$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));
});
正如 v3.0 文档中所示:
socket.onAny((event, ...args) => {
console.log(`got ${event}`);
});
当前(2013 年 4 月)GitHub 文档中关于暴露的事件提到了一个socket.on('anything')
。"anything"似乎是自定义事件名称的占位符,而不是可以捕获任何事件的实际关键字。
我刚刚开始使用 Web 套接字和 Node.JS,并立即需要处理任何事件,以及发现发送了哪些事件。不太相信 socket.io 缺少此功能。
socket.io-client 1.7.3
截至 2017 年 5 月,无法使任何其他解决方案完全按照我想要的方式工作 - 制作了一个拦截器,使用 at 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)
}
})
引用:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
- https://github.com/socketio/socket.io-client/blob/ff4cb3eed04a95c9725b8aaba8b64fa9fa1ca413/lib/socket.js#L257
因为你的问题在要求解决方案时非常笼统,所以我会提出这个不需要破解代码,只需要改变你如何使用套接字的问题。
我刚刚决定让我的客户端应用程序发送完全相同的事件,但有效负载不同。
socket.emit("ev", { "name" : "miscEvent1"} );
socket.emit("ev", { "name" : "miscEvent2"} );
在服务器上,类似...
socket.on("ev", function(eventPayload) {
myGenericHandler(eventPayload.name);
});
我不知道总是使用相同的事件是否会导致任何问题,也许是某种大规模的碰撞,但这很好地满足了我的目的。
在 Socket.IO 存储库问题页面上对此主题进行了长时间的讨论。 那里发布了各种解决方案(例如,用 EventEmitter2 覆盖 EventEmitter)。 LMJABREU 几周前发布了另一种解决方案:一个名为 socket.io-wildcard 的 npm 模块,它将通配符事件修补到 Socket.IO 上(适用于当前 Socket.IO,~0.9.14)。
尽管这是一个老问题,但我也有同样的问题,并使用 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');
})
我找到的所有方法(包括 socket.io 通配符和套接字通配符)都对我不起作用。显然 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
};
这可能也是其他人的解决方案。但是,ATM我不完全明白为什么没有其他人似乎对现有的"解决方案"有问题?!?有什么想法吗?也许这是我的旧节点版本(0.10.31)...
@Matthias 霍普夫答案
更新了 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
};
在 v4 中,Socket.IO 具有 Catch-all 侦听器。例如:
socket.prependAny(() => {
console.log("This will be fired first");
});
我正在使用 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}]`);
}
});
- keyup事件处理程序更改焦点不适用于快速键入
- Webpack/Rect:遵循egghead.io教程,但出现错误:您可能需要一个合适的加载程序来处理此文件类型
- 提示使用服务器端事件处理程序激活JavaScript
- 将事件处理程序绑定到任何可能的事件
- 正在将事件处理程序添加到不存在的类
- 在AJAX回调和呈现PIXIJS之间处理程序流时遇到了问题
- Adobe Edge:动画完成时添加onComplete处理程序
- 是否可以从输入处理程序中确定输入的类型
- 在MVVM视图模型中处理应用程序范围的元素
- 在循环中附加事件处理程序时出现浏览器性能问题
- 在同一个javascript事件处理程序中调用不同的函数
- 有没有一种方法可以让内联事件处理程序在元素创建后立即执行
- 检查事件处理程序参数
- 实现延迟的jquery更改事件处理程序
- 如何使用Python/Selenium网络驱动程序处理Angularjs/Javascript下拉列表
- 在 AJAX 完成之前,不要让其他处理程序处理
- 如何使用硒铬驱动程序处理地理位置弹出窗口
- 如何使用硒网络驱动程序处理 onblur 事件
- 是否有一种方法为chrome打包应用程序处理Http BasicAuthentication
- Ajax加载程序处理问题