HTML5 doctor网站有一篇关于服务器发送事件的优秀文章,但是我也会在这里提供一个(相对)简短的摘要。
服务器发送事件本质上是一种长时间运行的HTTP连接,使用了特殊的MIME类型(text/event-stream
)以及提供了EventSource
API的用户代理。这些因素共同构成了服务器和客户端之间的单向连接,可以从服务器向客户端发送消息。
在服务器端,操作非常简单。你只需要设置以下HTTP头即可:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
一定要用代码200
回应,而不是204
或其他任何代码,因为这会导致兼容的用户代理断开连接。另外,请确保不要在服务器端结束连接。现在,您可以自由地开始向该连接推送消息。在nodejs(使用express)中,可能如下所示:
app.get("/my-stream", function(req, res) {
res.status(200)
.set({ "content-type" : "text/event-stream"
, "cache-control" : "no-cache"
, "connection" : "keep-alive"
})
res.write("data: Hello, world!\n\n")
})
在客户端,您只需使用EventSource
API,如您所指出的:
var source = new EventSource("/my-stream")
source.addEventListener("message", function(message) {
console.log(message.data)
})
基本上就是这样了。
实际上,服务器和客户端通过一种相互约定的方式保持连接活跃。只要服务器认为必要,就会让连接保持活跃。如果服务器想要终止连接,它可以选择在客户端下次尝试连接时使用 204 No Content
进行响应来终止连接。这将导致客户端停止尝试重新连接。我不确定是否有一种方式可以以告知客户端不要重新连接的方式结束连接,从而跳过客户端尝试重新连接一次。
正如前面提到的,客户端也会保持连接活跃,并在连接断开时进行重新连接。重新连接的算法在规范中进行了说明,非常简单明了。
然而,我到目前为止几乎没有涉及的一个极其重要的部分是 MIME 类型。MIME 类型定义了传输中消息的格式。请注意,它并不规定消息内容的格式,而只规定消息本身的结构。MIME 类型非常简单明了。消息本质上是信息键值对。键必须是预定义的一组键之一:
- id - 消息的 ID
- data - 实际数据
- event - 事件类型
- retry - 用户代理在重试失败的连接之前应等待的毫秒数
其他任何键都应该被忽略。消息是通过使用两个换行符 \n\n
来分隔的。
以下是一个有效的消息(最后的换行符添加了冗余):
data: Hello, world!
\n
客户端将看到:Hello, world!
。
如此:
data: Hello,
data: world!
\n
客户端将看到如下内容:
Hello,\nworld!
。
这基本上概括了服务器推送事件的内容:一个长时间运行的非缓存 http 连接、一个 MIME 类型和一个简单的 JavaScript API。
如果您想了解更多信息,我强烈建议阅读
规范。它很简短,并且描述得非常清楚(尽管服务器端的要求可能需要更好地总结一下)。我强烈建议阅读它以获得特定 HTTP 状态代码的预期行为的信息,例如。