SSE 实现服务端长连接传数据

@zgcwkj  2024年06月22日

分类:

网站 代码 

Server-Sent Events 协议,实现服务端长连接传数据

介绍

Server-Sent Events (SSE) 是一种服务器向浏览器单向发送事件通知的技术,这种方法允许服务器在有新事件时实时地将更新推送到客户端,而不需要客户端轮询服务器以获取更新。SSE 是建立在 HTTP 协议之上的,因此它使用简单的 HTTP GET 请求与服务器建立连接。

主要特征

  • 单向通信:只能由服务器向客户端推送消息,客户端不能通过这个连接发送消息给服务器。
  • 基于文本:SSE 传输的数据是基于文本的,通常是 UTF-8 编码的。
  • 重连机制:如果连接被关闭,浏览器会自动尝试重新连接。
  • 事件标识:服务器可以为发送的事件指定事件类型和ID,客户端可以根据这些信息进行相应的处理。

使用场景

  • 实时通知
  • 聊天应用
  • 股票或其它实时数据的更新

优点

  • 简单易用,使用标准的HTTP协议。
  • 兼容性良好,大部分现代浏览器都支持SSE。
  • 内置自动重连机制。

缺点

  • 只支持文本数据,不可直接发送二进制数据。
  • 只能实现服务器到客户端的单向通讯。

后端接口

  • C#
[HttpGet, AllowAnonymous]
public async IAsyncEnumerable<string> GetDataStream()
{
    var dataItems = new List<string> { "Item1", "Item2", "Item3", "Item4", "Item5" };
    foreach (var item in dataItems)
    {
        //使用迭代器返回数据项
        yield return item;
        //模拟数据生成的延时
        await Task.Delay(1000);
    }
}

[HttpGet, AllowAnonymous]
public async Task GetDataStream(CancellationToken cancellationToken)
{
    var response = Response;
    response.Headers.Add("X-Accel-Buffering", "no");//取消Nginx缓存
    response.Headers.Add("Content-Type", "text/event-stream");
    response.Headers.Add("Cache-Control", "no-cache");
    for (int i = 0; i < 10; i++)
    {
        //如果客户端断开连接,则退出循环
        if (cancellationToken.IsCancellationRequested) break;
        //模拟实时返回数据项
        await response.WriteAsync($"data: Message {i}\n\n");
        await response.Body.FlushAsync();
        //模拟数据生成的延时
        await Task.Delay(1000);
    }
}
  • PHP
<?php
//ini_set('display_errors', 1);
//error_reporting(E_ALL);
//设置头部 SSE 应答
header('X-Accel-Buffering: no'); //取消Nginx缓存
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

//函数,生成SSE数据格式
function sendMsg($data) {
    echo "id: ". time() . PHP_EOL;
    echo "data: $data" . PHP_EOL.PHP_EOL;
    ob_flush();
    flush();
}

//发送数据
while (true) {
    $data = date("h:i:s", time());
    if (isset($_REQUEST["data"])) $data = $data . "_" .$_REQUEST["data"];
    //发送数据
    sendMsg($data);
    //休眠1秒
    sleep(1);
}

前端调用

  • JavaScript
if (!!window.EventSource) {
  var source = new EventSource('/GetDataStream');
  source.onmessage = function(event) {
    console.log(event.data);
  };
  source.onerror = function(error) {
    console.error("SSE 出现错误:", error);
  };
} else {
  console.log("浏览器不支持 SSE");
}


评论已关闭

Top