Node.js SSE res.write() 未在流中发送数据

问题描述 投票:0回答:4

我正在尝试在NodeJs中添加SSE(服务器发送事件),但是当我使用

res.write()
发送响应时,数据没有被发送,而是只有在写入
res.end()
之后所有数据才会同时发送。

我已经在 Github、StackOverflow 上找到了很多关于这个问题的帖子,并且到处都提到在每个

res.flush()
之后使用
res.write()
但这对我来说也不起作用,而且我也没有明确使用任何压缩模块。

服务器端代码

任何人都可以告诉我有什么办法可以让这项工作成功吗?

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!'))

客户端代码

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

解决方案 - 我使用 nginx 进行反向代理,这就是发生这种情况的原因,所以我尝试了这个解决方案并且它有效:)

事件源/服务器通过 Nginx 发送事件

node.js server-sent-events
4个回答
7
投票

如果您的 Express 服务器位于防火墙或代理服务器后面,它们通常会等到服务器关闭连接后再发送整个响应。相反,您需要在浏览器和服务器之间建立允许

'Connection': 'keep-alive'
的连接。


3
投票

就我而言,问题出在压缩中间件上。删除任何 SSE 请求的压缩中间件后,它再次正常工作。


0
投票

在我使用 Next.js API 的情况下,我之前是这样写的:

res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

添加此行后,它起作用了:

res.setHeader('Content-Encoding', 'none');

-3
投票

在您的示例中,为了防止完成整个迭代以发送事件,您需要在

res.end()
之后添加
res.write()
。 这样每个事件都会在 1 秒后发送。

function countdown(res, count) {
  res.write("data: " + count + "\n\n")
  res.end() // <-- add after each event
  if (count)
    setTimeout(() => countdown(res, count-1), 1000)
  else
    res.end()
}
© www.soinside.com 2019 - 2024. All rights reserved.