在Node.js中实现服务器发送事件的简单方法?

Jas*_*ch1 8 javascript node.js server-sent-events

我环顾四周,好像在Node.js中实现SSE的所有方法都是通过更复杂的代码,但似乎应该有一种更简单的方式来发送和接收SSE.是否有任何API或模块使这更简单?

Bre*_*rne 17

这是一个快速服务器,每秒发送一个服务器发送事件(SSE),从10倒数到0:

const express = require('express')

const app = express()
app.use(express.static('public'))

app.get('/countdown', function(req, res) {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
  })
  countdown(res, 10)
})

function countdown(res, count) {
  res.write("data: " + count + "\n\n")
  if (count)
    setTimeout(() => countdown(res, count-1), 1000)
  else
    res.end()
}

app.listen(3000, () => console.log('SSE app listening on port 3000!'))
Run Code Online (Sandbox Code Playgroud)

将上面的代码放入一个文件(index.js)并运行它: node index

接下来,将以下HTML放入文件(public/index.html):

<html>
<head>
  <script>
  if (!!window.EventSource) {
    var source = new EventSource('/countdown')

    source.addEventListener('message', function(e) {
      document.getElementById('data').innerHTML = e.data
    }, false)

    source.addEventListener('open', function(e) {
      document.getElementById('state').innerHTML = "Connected"
    }, false)

    source.addEventListener('error', function(e) {
      const id_state = document.getElementById('state')
      if (e.eventPhase == EventSource.CLOSED)
        source.close()
      if (e.target.readyState == EventSource.CLOSED) {
        id_state.innerHTML = "Disconnected"
      }
      else if (e.target.readyState == EventSource.CONNECTING) {
        id_state.innerHTML = "Connecting..."
      }
    }, false)
  } else {
    console.log("Your browser doesn't support SSE")
  }
  </script>
</head>
<body>
  <h1>SSE: <span id="state"></span></h1>
  <h3>Data: <span id="data"></span></h3>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

在浏览器中,打开localhost:3000并观看SSE倒计时.

  • 我会说这个答案是“在Node.js中实现服务器发送事件”的最简单方法 (3认同)
  • 你能帮我吗,我正在做你提到的同样的事情,但我的数据是在 `res.end()` 一次发送的,我什至在每次 `res.write 之后尝试过 `res.flush()` ()` 但没有任何效果。我的问题在这里/sf/ask/4298877691/ (3认同)

bay*_*ezy 10

服务器发送的事件非常简单.看看我的两部分博客文章.

  1. http://bayn.es/real-time-web-applications-with-server-sent-events-pt-1/
  2. http://bayn.es/real-time-web-apps-with-server-sent-events-pt-2/

  • 尽管有点复杂,但我还是喜欢使用Redis的想法。它很容易设置,并且功能非常强大而强大。使用它的内部功能,它将消除对渠道及其所有开发的需求。值得花时间学习。好例子! (3认同)

cod*_*ami 7

我在这里添加了一个简单的 SSE 实现。它只是一个 Node.js 文件。

您可以在此处查看结果:https : //glossy-ox.glitch.me/

const http = require('http');
const port = process.env.PORT || 3000;

const server = http.createServer((req, res) => {
  // Server-sent events endpoint
  if (req.url === '/events') {
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
    });

    const refreshRate = 1000; // in milliseconds
    return setInterval(() => {
      const id = Date.now();
      const data = `Hello World ${id}`;
      const message =
        `retry: ${refreshRate}\nid:${id}\ndata: ${data}\n\n`;
      res.write(message);
    }, refreshRate);
  }

  // Client side
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.end(`
    <!DOCTYPE html>
    <html lang="en" dir="ltr">
      <head>
        <meta charset="utf-8">
        <title>SSE</title>
      </head>
      <body>
        <pre id="log"></pre>
      </body>
      <script>
        var eventSource = new EventSource('/events');
        eventSource.onmessage = function(event) {
          document.getElementById('log').innerHTML += event.data + '<br>';
        };
      </script>
    </html>
  `);
});

server.listen(port);

server.on('error', (err) => {
  console.log(err);
  process.exit(1);
});

server.on('listening', () => {
  console.log(`Listening on port ${port}`);
});
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的答案,因为它确实使用了任何第三方依赖项:)但是我想指出 `res.end(message)` 应该替换为 `setInterval(() =&gt; res.write(message), 1000) ` 因为连接不应该被终止,所以应该始终使用相同的连接,但您当前的代码导致客户端重新连接并每 1 秒创建一个新连接 (2认同)
  • 需要注意的是 `'Connection': 'keep-alive'` 不能用于 HTTP/2。如果使用 HTTP/2,则需要在设置标头之前检查 `res.httpVersionMajor`。另外,您应该每 15 秒左右发送一个保持活动数据包(尽管您的示例每秒发送一个测试数据包)。空注释行 `:\n` 就可以了。 (2认同)

小智 7

如果您使用的是 Express,这是最简单的方法https://www.npmjs.com/package/express-sse

关于BE:

const SSE = require('express-sse');

const sse = new SSE();

...

app.get('/sse', sse.init);

...

sse.send('message', 'event-name');
Run Code Online (Sandbox Code Playgroud)

关于FE:

const EventSource = require('eventsource');

const es = new EventSource('http://localhost:3000/sse');

es.addEventListener('event-name', function (message) {
  console.log('message:', message)
});
Run Code Online (Sandbox Code Playgroud)


小智 -42

您应该能够使用Socket.io来做这样的事情。首先,您需要使用 来安装它npm install socket.io。从那里开始,在您的代码中您将希望拥有var io = require(socket.io);

您可以查看Socket.IO 给出的更深入的示例

你可以在服务器上使用这样的东西:

var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('../..')(server);
var port = process.env.PORT || 3000;

server.listen(port, function () {
  console.log('Server listening at port ' + port);
});

app.use(express.static(__dirname + '/public'));

io.on('connection', function (socket) {
    socket.emit('EVENT_NAME', {data});
});
Run Code Online (Sandbox Code Playgroud)

在客户端上是这样的:

<script src="socket_src_file_path_here"></script>
<script>
  var socket = io('http://localhost');
  socket.on('EVENT_NAME', function (data) {
    console.log(data);
    //Do whatever you want with the data on the client
  });
</script>
Run Code Online (Sandbox Code Playgroud)

  • 我绝对**反对**这种做法!我已经使用 Socket.IO 很长时间了,我可以肯定地说,随着时间的推移,你将开始克服很多痛苦。服务器端事件是**单向**,而套接字是**双向**。一种是请求响应型,另一种是长连接型。差异是巨大的,你绝对不需要套接字 - 你将不得不处理重新连接、垃圾邮件防护、服务器宕机,也许还有集群。使用简单的 SSE,它已经在浏览器中实现了!请参阅其他答案! (45认同)
  • OP 要求使用 SSE,而不是 WebSocket。 (39认同)