新答案:
只需使用 socket.io,它就更简单更好了!
https://www.npmjs.com/package/socket.io#in-conjunction-with-express
基本设置:
const express = require('express');
const PORT = process.env.PORT || 5000;
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io')(server);
// listen to socket connections
io.on('connection', function(socket){
// get that socket and listen to events
socket.on('chat message', function(msg){
// emit data from the server
io.emit('chat message', msg);
});
});
// Tip: add the `io` reference to the request object through a middleware like so:
app.use(function(request, response, next){
request.io = io;
next();
});
server.listen(PORT);
console.log(`Listening on port ${PORT}...`);
在任何路由处理程序中,您都可以使用 socket.io:
app.post('/post/:post_id/like/:user_id', function likePost(request, response) {
//...
request.io.emit('action', 'user liked your post');
})
客户端:
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
$(function () {
var socket = io();
$('form').submit(function(e){
e.preventDefault(); // prevents page reloading
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
});
});
</script>
完整示例:https://socket.io/get-started/chat/
原答案
某人(用户:https://stackoverflow.com/users/451634/benny-neugebauer | 来自本文:addEventListener on custom object)从字面上给了我一个提示,告诉我如何在没有任何其他包的情况下实现这一点,除了 express!我已经成功了!
首先,导入Node的EventEmitter:
const EventEmitter = require('events');
然后创建一个实例:
const Stream = new EventEmitter();
然后为事件流创建一个 GET 路由:
app.get('/stream', function(request, response){
response.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
Stream.on("push", function(event, data) {
response.write("event: " + String(event) + "\n" + "data: " + JSON.stringify(data) + "\n\n");
});
});
在这个 GET 路由中,你写回请求是 200 OK,content-type 是 text/event-stream,没有缓存,并且是 keep-alive。
您还将调用 EventEmitter 实例的 .on 方法,该方法接受 2 个参数:要侦听的事件字符串和处理该事件的函数(该函数可以使用给定的参数)
现在....发送服务器事件所需要做的就是调用 EventEmitter 实例的 .emit 方法:
Stream.emit("push", "test", { msg: "admit one" });
第一个参数是你要触发的事件的字符串(确保它与GET路由中的相同)。 .emit 方法的每个后续参数都将传递给侦听器的回调!
就是这样!
由于您的实例是在路由定义之上的范围内定义的,因此您可以从任何其他路由调用 .emit 方法:
app.get('/', function(request, response){
Stream.emit("push", "test", { msg: "admit one" });
response.render("welcome.html", {});
});
由于 JavaScript 作用域的工作原理,您甚至可以将该 EventEmitter 实例传递给其他函数,甚至可以从其他模块传递:
const someModule = require('./someModule');
app.get('/', function(request, response){
someModule.someMethod(request, Stream)
.then(obj => { return response.json({}) });
});
在一些模块中:
function someMethod(request, Stream) {
return new Promise((resolve, reject) => {
Stream.emit("push", "test", { data: 'some data' });
return resolve();
})
}
就这么简单!无需其他软件包!
这里是 Node 的 EventEmitter 类的链接:https://nodejs.org/api/events.html#events_class_eventemitter
我的例子:
const EventEmitter = require('events');
const express = require('express');
const app = express();
const Stream = new EventEmitter(); // my event emitter instance
app.get('/stream', function(request, response){
response.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
Stream.on("push", function(event, data) {
response.write("event: " + String(event) + "\n" + "data: " + JSON.stringify(data) + "\n\n");
});
});
setInterval(function(){
Stream.emit("push", "test", { msg: "admit one" });
}, 10000)
更新:
我创建了一个更易于使用且不会导致内存泄漏的模块/文件!
const Stream = function() {
var self = this;
// object literal of connections; IP addresses as the key
self.connections = {};
self.enable = function() {
return function(req, res, next) {
res.sseSetup = function() {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
})
}
res.sseSend = function(id, event, data) {
var stream = "id: " + String(id) + "\n" +
"event: " + String(event) + "\n" +
"data: " + JSON.stringify(data) +
"\n\n";
// console.log(id, event, data, stream);
res.write(stream);
}
next()
}
}
self.add = function(request, response) {
response.sseSetup();
var ip = String(request.ip);
self.connections[ip] = response;
}.bind(self);
self.push_sse = function(id, type, obj) {
Object.keys(self.connections).forEach(function(key){
self.connections[key].sseSend(id, type, obj);
});
}.bind(self);
}
/*
Usage:
---
const express = require('express');
const Stream = require('./express-eventstream');
const app = express();
const stream = new Stream();
app.use(stream.enable());
app.get('/stream', function(request, response) {
stream.add(request, response);
stream.push_sse(1, "opened", { msg: 'connection opened!' });
});
app.get('/test_route', function(request, response){
stream.push_sse(2, "new_event", { event: true });
return response.json({ msg: 'admit one' });
});
*/
module.exports = Stream;
脚本位于此处 - https://github.com/ryanwaite28/script-store/blob/master/js/express-eventstream.js