什么是SSE
SSE(Server-Sent Events)是一种用于实现服务器主动向客户端推送数据的技术,也被称为“事件流”(Event Stream)。它基于 HTTP 协议,利用了其长连接特性,在客户端与服务器之间建立一条持久化连接,并通过这条连接实现服务器向客户端的实时数据推送。
SSE技术的基本原理
- 客户端向服务器发送一个GET请求,带有指定的header,表示可以接收事件流类型,并禁用任何的事件缓存。
- 服务器返回一个响应,带有指定的header,表示事件的媒体类型和编码,以及使用分块传输编码(chunked)来流式传输动态生成的内容。
- 服务器在有数据更新时,向客户端发送一个或多个名称:值字段组成的事件,由单个换行符分隔。事件之间由两个换行符分隔。服务器可以发送事件数据、事件类型、事件ID和重试时间等字段。
- 客户端使用EventSource接口来创建一个对象,打开连接,并订阅onopen、onmessage和onerror等事件处理程序来处理连接状态和接收消息。
- 客户端可以使用GET查询参数来传递数据给服务器,也可以使用close方法来关闭连接。
技术实现
SSE 基于 HTTP 协议,利用了其长连接特性,通过浏览器向服务器发送一个 HTTP 请求,建立一条持久化的连接。
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
数据格式
SSE 可以传输文本和二进制格式的数据,但只支持单向数据流,即只能由服务器向客户端推送数据。
SSE适用于场景
SSE适用场景是指服务器向客户端实时推送数据的场景,例如:
- 股票价格更新:服务器可以根据股市的变化,实时地将股票价格推送给客户端,让客户端能够及时了解股票的走势和行情。
- 新闻实时推送:服务器可以根据新闻的更新,实时地将新闻内容或标题推送给客户端,让客户端能够及时了解最新的新闻动态和信息。
- 在线聊天:服务器可以根据用户的发送,实时地将聊天消息推送给客户端,让客户端能够及时收到和回复消息。
- 实时监控:服务器可以根据设备的状态,实时地将监控数据或报警信息推送给客户端,让客户端能够及时了解设备的运行情况和异常情况。
SSE适用场景的特点
- 数据更新频繁:服务器需要不断地将最新的数据推送给客户端,保持数据的实时性和准确性。
- 低延迟:服务器需要尽快地将数据推送给客户端,避免数据的延迟和过期。
- 单向通信:服务器只需要向客户端推送数据,而不需要接收客户端的数据。
服务端基本响应格式
SSE响应主要由一系列以两个换行符分隔的事件组成。每个事件可以包含以下字段:
- data:事件的数据。如果数据跨越多行,每行都应该以data:开始。
- id:事件的唯一标识符。客户端可以使用这个ID来恢复事件流。
- event:自定义事件类型。客户端可以根据不同的事件类型来执行不同的操作。
- retry:建议的重新连接时间(毫秒)。如果连接中断,客户端将等待这段时间后尝试重新连接。
.NET 8 实现SSE
using Microsoft.AspNetCore.Mvc;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace SSE.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class SSEController : ControllerBase
{
[HttpGet]
public async Task SSEResponse(CancellationToken cancellationToken)
{
Response.Headers.Add("Content-Type", "text/event-stream;charset=utf-8");
Response.Headers.Add("Cache-Control","no-cache");
Response.Headers.Add("Connection", "keep-alive");
for (var i = 0; true; ++i)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
await Response
.WriteAsync($"data: Controller {i} at {DateTime.Now}\r\r");
await Response.Body.FlushAsync();
await Task.Delay(5 * 1000);
}
}
// GET api/<SSEController>/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
// POST api/<SSEController>
[HttpPost]
public void Post([FromBody] string value)
{
}
// PUT api/<SSEController>/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/<SSEController>/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}