c# 实现 Server-Sent Events (SSE),服务器单方面消息推送 [案例版]
游览器通讯技术其实有很多,相较于 WebSocket 而言,Server-Sent Events (简称SSE)更少被人知晓,具体实践也较少。
但是,实现却是简单的,其中 IE / Edge 几乎根本不支持 SSE。
这也是WebSocket活的原因,相比 websocket的复杂来讲,SSE相对来讲实现就简单多了,如果WebSocket是全双工,那么SSE就是半双工通信。
而且,在.NET 技术栈里 SignalR 其实是包含了前端的ajax通讯、websocket通讯以及SSE(游览器事件)通讯。
但是也不影响,了解一下SSE的魅力。
SSE 协议原理
SSE 协议很简单,本质上是一个客户端发起的 HTTP Get 请求,服务器在接到该请求后,返回 200 OK 状态,同时附带以下 Headers
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
SSE 的 MIME Type 规定为 text/event-stream
SSE 肯定不允许缓存
SSE 是一个一直打开的 TCP 连接,所以 Connection 为 Keep-Alive
SSE协议通讯基本格式
[field]: value\n
其中 [field] 中的field 可以取四种key
- id
- data
- event
- retry
id
数据标识符用id字段表示,相当于每一条数据的编号。
浏览器用lastEventId属性读取这个值。一旦连接断线,浏览器会发送一个 HTTP 头,里面包含一个特殊的Last-Event-ID头信息,将这个值发送回来,用来帮助服务器端重建连接。因此,这个头信息可以被视为一种同步机制。
data
数据内容用data字段表示。
如果数据很长,可以分成多行,最后一行用\n\n结尾,前面行都用\n结尾。
event
event字段表示自定义的事件类型,默认是message事件。浏览器可以用addEventListener()监听该事件。
retry
服务器可以用retry字段,指定浏览器重新发起连接的时间间隔。
代码实现
在实际情况中 可能用不上SignalR 或者 websocket 这样全双工,太重的框架和技术,我们就可以用基于http协议本身的sse协议的实现我们想要的推送功能。
ASP.NET MVC
HomeController
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult ServerSentEvents()
{
Random random = new Random();
string _event = "message";
string data = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
if (random.Next(0, 10) % 3 == 0)
{
data = "新消息";
_event = "NewMsg";
}
Response.ContentType = "text/event-stream";
return Content($"retry:{1000}\nevent:{_event}\nid:{DateTime.Now.Ticks}\ndata:{data}\n\n");
}
}
Index.cshtml
<h>主页</h>
<div id="result"></div>
<script type="text/javascript">
if (typeof (EventSource) !== "undefined") {
var source = new EventSource("../home/ServerSentEvents");
source.onopen = function (event) {
console.log(source.readyState);
console.log(event);
};
source.onerror = function (event) {
console.log(source.readyState);
console.log(event);
document.getElementById("result").innerHTML += "服务关闭 <br>";
};
source.onmessage = function (event) {
console.log(source.readyState);
console.log(event);
document.getElementById("result").innerHTML += event.data + "<br>";
};
source.addEventListener("NewMsg", function (e) {
console.log("唤醒新事件");
console.log(e);
document.getElementById("result").innerHTML += e.data + "<br>";
});
}
else {
document.getElementById("result").innerHTML = "抱歉,你的浏览器不支持 server-sent 事件...";
}
</script>
结果如下
实现结果如下:

以前一直不懂,现在懂了。也实现了。
又掌握一个知识点,欧耶。
原理参考
可以参考这一篇的 概念 https://zhuanlan.zhihu.com/p/21308648
或者 阮一峰 大佬的 这一篇 https://www.ruanyifeng.com/blog/2017/05/server-sent_events.html
代码地址
https://github.com/kesshei/WebSSEDemo.git
https://gitee.com/kesshei/WebSSEDemo

浙公网安备 33010602011771号