SSE 的全称是 Server Sent Events,即服务器推送事件。它是一种基于 HTTP 的服务器到客户端的单向(半双工)通信机制,使服务器能够主动将实时数据推送给客户端,而不需要客户端多次发起请求。 官方文档:https://developer.mozilla.org/en-US/docs/Web/API/EventSource
常规的HTTP请求响应流程无法做到服务器主动推送数据到客户端,SSE可以解决此问题。
实时更新订阅数据、实时通知、实时日志监控、实时数据统计、简单的文本数据传输。
// 这行代码用于关闭输出缓冲。关闭后,脚本的输出将立即发送到浏览器,而不是等待缓冲区填满或脚本执行完毕。
ini_set('output_buffering', 'off');
// 这行代码禁用了 zlib 压缩。通常情况下,启用 zlib 压缩可以减小发送到浏览器的数据量,但对于服务器发送事件来说,实时性更重要,因此需要禁用压缩。
ini_set('zlib.output_compression', false);
// 这行代码使用循环来清空所有当前激活的输出缓冲区。ob_end_flush() 函数会刷新并关闭最内层的输出缓冲区,@ 符号用于抑制可能出现的错误或警告。
while (@ob_end_flush()) {}
// 这行代码设置 HTTP 响应的 Content-Type 为 text/event-stream,这是服务器发送事件(SSE)的 MIME 类型。
header('Content-Type: text/event-stream');
// 这行代码设置 HTTP 响应的 Cache-Control 为 no-cache,告诉浏览器不要缓存此响应。
header('Cache-Control: no-cache');
// 这行代码设置 HTTP 响应的 Connection 为 keep-alive,保持长连接,以便服务器可以持续发送事件到客户端。
header('Connection: keep-alive');
// 这行代码设置 HTTP 响应的自定义头部 X-Accel-Buffering 为 no,用于禁用某些代理或 Web 服务器(如 Nginx)的缓冲。这有助于确保服务器发送事件在传输过程中不会受到缓冲影响
header('X-Accel-Buffering: no');
/**
* @function 封装sse格式的数据
* @param $data string
* @return string
*/
function sse($data) {
//data:\n\n不能少,sse固定格式
return "data:{$data}\n\n";
}
// 开启输出缓冲
ob_start();
while (true) {
$json = json_encode(['data' => ['time' => date('Y-m-d H:i:s')]], JSON_UNESCAPED_UNICODE);
echo sse($json);
//刷新缓冲区
ob_flush();
//将输出缓冲区的内容立即发送到客户端
flush();
sleep(1);
}
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
if(!! window.EventSource) {
var sse = new EventSource('http://127.0.0.1/test/sse.php');
//通信事件
sse.onmessage = function (event) {
var response = JSON.parse(event.data);
console.log(response.data.time);
};
// 打开事件
sse.onopen = function (event) { console.log('连接成功'); };
//关闭事件
sse.onclose = function(event) {console.log('连接关闭');};
//错误事件
sse.onerror = function (event) {console.error('连接失败');};
} else {
alert('您的浏览器不支持SSE');
}
</script>
</html>
/**
* @function 与客户端server send event通信方式
* @param $callback callable 回调,若返回数组代表要输出json,返回null代表本次循环不进行输出
* @param $millisecond int 数据分发间隔,单位:毫秒
* @return string
* @other void
*/
function sse($callback, $millisecond = 1000) {
set_time_limit(0);
ini_set('output_buffering', 'off');
ini_set('zlib.output_compression', false);
while (@ob_end_flush()) {}
header('Content-Type: text/event-stream; Charset=UTF-8');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('X-Accel-Buffering: no');
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: *');
header('Access-Control-Allow-Headers: *');
ob_start();
while (true) {
$callback_res = $callback();
if($callback_res !== null) {
$data = json_encode($callback_res, JSON_UNESCAPED_UNICODE);
echo "data:{$data}\n\n";
}
ob_flush();
flush();
usleep($millisecond * 1000);
}
}
//调用
sse(function() {
if('业务逻辑数据存在') {
return ['k' => 'v'];
}
return null;
}, 1000);
协议:SSE是基于HTTP协议,而WebSocket则是独立的协议,它们都可以在浏览器和服务器之间建立持久的连接。
SSE通过HTTP协议传输的数据格式是文本(通常是JSON格式),因此它适合用于传输简单的文本数据或者事件。而WebSocket可以传输文本和二进制数据,在处理音频、视频等大型数据时更有优势。
SSE基于半双工模式,服务器可以通过发送事件流(event stream)来主动推送数据给客户端。客户端通过监听这些事件来接收数据。而WebSocket是全双工通信协议,客户端和服务器可以随时发送和接收数据。
IE10及以上支持 WebSocket。但IE都不兼容SSE,并且不同浏览器对SSE兼容性不一样,可通过Polyfill解决,官网:https://developer.mozilla.org/en-US/docs/Glossary/Polyfill。