我在Golang使用这个令人惊叹的SSE服务器(https://github.com/r3labs/sse)Heroku。
这里有一个超时限制:https://devcenter.heroku.com/articles/request-timeout#long-轮询和流式响应:
如果您正在发送流式响应,例如服务器发送的事件,您需要检测客户端何时挂断,并确保应用服务器立即关闭连接。如果服务器在不发送任何数据的情况下保持连接打开55秒,您将看到请求超时。
我知道在WebSocket的世界里有Keep Alive ping的概念。
我正在尝试使用此代码:
go func() {
for range time.Tick(time.Second * 1) {
fmt.Println("a second")
sseServer.Publish("test", &sse.Event{Data: []byte("ping")})
}
}()
使用这样一个简单的服务器:
httpServer := &http.Server{
//...
ReadTimeout: "10s",
WriteTimeout: "10s",
}
但它不起作用。呼叫在10秒钟后关闭(并发出10次ping(。
我认为它在赫罗库也会失败。
我哪里错了?
我们可以只更改这些SSE调用的超时吗
还有别的办法吗
更新
我不需要准确检测断开连接的客户端,我根本不在乎。当服务器上发生什么事情时,我用它来刷新仪表板。
我不喜欢使用WebSocket来做一些简单的事情。
我想我没有很好地解释自己,因为我不太想使用ping来检测断开连接的客户端,而是因为我希望连接不会被中断(就像在Heroku上发生的那样(。
现在的情况
局部
如果我在Windows上完全删除ReadTimeout
字段,但在Docker linux容器上也删除了,则连接不会停止,一切正常。
论HEROKU
由于在Heroku上,连接每55秒就会中断一次,我在第一篇文章中告诉过你,我用那个非常简单的代码尝试了这个循环,它成功了:SSE调用不再关闭!
剩下的问题
- 如何在任何情况下为所有其他调用(而不是SSE(设置默认
ReadTimeout
;我认为最好的做法是设置一个默认的ReadTimeout
怎么办
您不需要ReadTimeout;在初始EventSource/server Sent Events(SSE(连接之后,服务器将永远不会从客户端读取任何内容。
因此,使用SSE连接设置默认读取超时不是最佳做法,因为该读取超时总是会被命中。您永远无法通过最初的SSE GET请求发送更多的数据。
你应该把SSE基本上看作是一个永远不会关闭的GET请求,因为它几乎就是这样。这意味着它在大多数代理服务器中都能很好地工作,而在它不工作的地方(代理服务器应用自己的超时(,客户端会自动重新连接,这实际上是websocket中没有的一个非常好的特性(尽管大多数websocket客户端库都实现了它(。
你可能想通读这篇文章,了解更多关于SSE的伟大(但不那么伟大(之处:https://www.smashingmagazine.com/2018/02/sse-websockets-data-flow-http2/
关于你的另一个问题,你可能正在寻找你的HTTP路由库,它将允许你对一些GET请求应用超时,而不是其他请求,但问题是为什么;如果您试图防止资源流失,那么应该在所有端点上均匀地应用这种保护。