概念
Sever-Sent Events(SSE) 可实现由服务端主动推送消息给客户端
特点:
- 基于 HTTP 协议
- 由服务端向客户端发送消息,只能单向发送
- 只支持文本消息
- 当不通过 HTTP / 2 使用时,SSE会受到最大连接数的限制(Chrome、Firefox 每个浏览器最多 6 个连接)
事件流格式
事件流仅仅是一个简单的文本数据流,文本应使用 UTF-8 格式编码。
每条消息后面都由一个空行作为分隔符。
- 例 1:客户端将收到 myevent 事件类型,消息为 xxxx\nyyyy
event: myevent
data: xxxx
data: yyyy
- 例 2:未指定事件类型,默认为 message 事件类型,消息为 zzzz
data: zzzz
- 例 3:冒号开头,表示注释,可以用来防止连接超时,服务器可以定期发送一条消息注释行,以保持连接不断。
: this is just a annotation
实战 Demo
- 效果图
- Web 客户端
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SSE Demo</title>
</head>
<body>
<div id="messages"></div>
<script>
const source = new EventSource('sse.php');
// 建立连接
source.onopen = function () {
var messages = document.getElementById('messages');
messages.innerHTML += 'connection is established' + '<br>';
};
// ping 事件类型消息
source.addEventListener("ping", function(event) {
var messages = document.getElementById('messages');
messages.innerHTML += 'ping: ' + event.data + '<br>';
});
// message 事件类型消息
source.onmessage = function(event) {
var messages = document.getElementById('messages');
messages.innerHTML += event.data + '<br>';
};
// 连接错误
source.onerror = function (event) {
var messages = document.getElementById('messages');
var data = 'connection state: ' + eventSource.readyState + ', error: ' + event
messages.innerHTML += data + '<br>';
};
</script>
</body>
</html>
- 服务端
<?php
// 禁用缓存
header("Cache-Control: no-cache");
// 指明 MIMI
header("Content-Type: text/event-stream");
// 使用持久连接
header('Connection: keep-alive');
while (true) {
// 发送 ping 事件类型消息
echo "event: ping\n";
echo 'data: {"time": "' . date('Y-m-d H:i:s'). '"}';
echo "\n\n";
if (time() % 5 === 0) {
// 未指定事件类型,默认为 message 事件类型
echo 'data: This is a message at time ' . date('Y-m-d H:i:s') . "\n\n";
}
ob_end_flush();
flush();
sleep(1);
}
参考
- https://developer.mozilla.org/zh-CN/docs/Web/API/Server-sent_events
- https://zhuanlan.zhihu.com/p/444011262
- https://github.red/talking-about-eventstream/