9

关于本规范:http ://www.w3.org/TR/eventsource/

如何关闭服务器上打开的连接?客户端很简单,只需调用close(),但我应该在服务器上做什么?直接杀了?

4

6 回答 6

7

因此,我四处寻找协议中内置的解决方案,但似乎没有。如果您的服务器调用response.emit('close')or response.end(),客户端会将其视为错误并尝试重新连接到服务器。(至少在 Chrome 的情况下,它会无限期地尝试重新连接,除非它认为网络错误是致命的)。

因此,您的客户端似乎必须以一种或另一种方式关闭连接。这留下了两个选择。第一个是简单地假设来自服务器的任何错误都应该关闭 EventSource。

const sse = new EventSource('/events')
sse.onmessage = m => console.log(m.data)
sse.onerror = () => sse.close()

上述内容仍有一些不足之处。我们假设网络错误是正常关闭,但情况可能并非如此。在某些情况下,我们确实需要重新连接行为。

所以相反,我们为什么不让客户端优雅地关闭自己!我们有一种方法可以从服务器向客户端发送消息,所以我们需要做的就是从服务器发送一条消息,上面写着“关闭我”。

// client.js
const maxReconnectTries = 3

let reconnectAttempts = 0
const sse = new EventSource('/events')
sse.onmessage = m => {
  const { type, data } = JSON.parse(m.data)
  if (type === 'close') sse.close()
  else console.log(data)
}
sse.onerror = () => {
  if (reconnectAttempts > maxReconnectTries) {
    sse.close()
    alert("We have a baaad network error!")
  } else {
    reconnectAttempts++
  }
}
// server.js
const express = require('express')


function sendEvent(res, type, data) {
  res.write(`data: ${JSON.stringify({ type, data })}\n\n`)
}

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

  let manualShutdown
  request.on('close', () => {
    console.log('disconnected.')
    clearTimeout(manualShutdown)  // prevent shutting down the connection twice
  })
  
  sendEvent(res, 'message', `Ping sent at ${new Date()}`)

  // when it comes time to shutdown the event stream (for one reason or another)
  setTimeout(() => {
    sendEvent(res, 'close', null)
    // give it a safe buffer of time before we shut it down manually
    manualShutdown = setTimeout(() => res.end(), clientShutdownTimeout)
  }, 10000)
}

const clientShutdownTimeout = 2000
const app = express()
app.get('/events', sseHandler)
app.listen(4000, () => console.log('server started on 4000'))

这涵盖了我们实现安全客户端/服务器所需的所有领域。如果服务器出现问题,我们会尝试重新连接,但如果出现故障仍然可以通知客户端。当服务器想要关闭连接时,它会要求客户端关闭连接。两秒钟后,如果客户端没有关闭连接,我们可以假设出现问题并关闭连接服务器端。

我们在这里所做的是在服务器发送的事件之上构建一个协议。它有一个非常简单的 api:{ "type": "close" }告诉客户端关闭服务器,并{ "type": "message", "data": {"some": "data" }告诉客户端这是一条常规消息。

于 2020-07-11T20:33:34.240 回答
4

节点.js:

http.createServer(function (req, res) {

    //...

    // client closes connection
    res.socket.on('close', function () {
      res.end();
      //...
    });

});

请参阅 node.js 中 SSE 服务器的实现示例:

https://github.com/Yaffle/EventSource/blob/master/nodechat/server.js

于 2011-10-07T10:02:32.507 回答
1

我猜你只是关闭连接(杀死它)。我还没有看到任何关于优雅断开的讨论。

于 2011-07-16T09:58:25.420 回答
1

您可以更改服务器发送的内容类型,而不是“文本/事件流”。这将关闭客户端事件源。

于 2012-06-04T09:56:11.057 回答
1

注意:如果你在 node.js 中使用包来管理服务器发送的事件,直接调用response.end()可能会导致包在之后发送额外的数据response.end(),这将导致服务器崩溃并出现“关闭后写入”错误。

response.end()我的解决方法不是直接调用,而是调用response.emit('close'),它允许包处理关闭。

http.ServerResponse > Event.close上的 Node.js 文档:

https://nodejs.org/api/http.html#http_event_close_1

于 2019-04-14T23:49:01.340 回答
0

如果从客户端关闭连接,则 res.end() 不是可行的方法,并且以后可能会导致 ERR_STREAM_WRITE_AFTER_END 错误。如果是这种情况,最好撤消在路由中添加的逻辑。

可以找到一个示例Node.JS Server Sent Events: Route continue to run after res.end() 导致 ERR_STREAM_WRITE_AFTER_END 错误

于 2020-01-21T00:04:10.073 回答