郭某人的网站

关于 / 留言

WEB 网页开发 Server-Sent Events 使用示例

WEB SSE 服务器发送事件的用法 C# ASP.NET ashx 一般处理程序


有时候进行网站开发会遇到消息推送、即时信息等功能需要,以往使用循环的异步网络请求实现“轮询”操作,但现在更推荐使用 HTML5 的 Server-Sent Events SSE 特性,此方法比多次循环的网络请求更加有效率,除了旧版的 Internet Explorer 外,现在主流的浏览器都支持此特性,这在浏览器调试器中是这样呈现的:

看起来只有一次请求,实则数据都集成在了 EventStream 里,下面用个 C# 和 ASP.NET 的一般处理程序配合前端实现简单的示例并讲解基本用法:

首先是前端与脚本代码,用来接收服务端推送的消息:

<p id="p1"></p>
<script>
   var source = new EventSource("Handler1.ashx", {
       withCredentials: true
   });
   source.onopen = function (event) {
       console.log("onopen", event)
   };
   source.onerror = function (event) {
       console.log("onerror", event)
       source.close()
   };
   //source.onmessage = function (event) {
   //    console.log("onmessage", event)
   //    document.getElementById("p1").innerHTML += event.data + "<br>";
   //};
   source.addEventListener("gett", function (event) {
       console.log("gett", event)
       document.getElementById("p1").innerHTML += event.data + "<br>";
   })
</script>

上面的代码中监听了一个名叫 gett 的事件并且注释了一段事件代码,这里的事件名称由服务器端定义,如果服务器端没有定义事件名称,那么将会执行到被注释的 onmessage 事件代码那里,定义了事件名称的话就会跳过 onmessage 事件;如果遇到了错误将会执行 onerror 事件里的代码,默认情况下遇到错误后会重新执行连接,所以我们在遇到错误时就关闭掉这个 EventSource;每第一次连接时就会执行 onopen 事件里的代码,包括发生错误后的重连。

前端的代码已结束,下面我们看看 ASP.NET 服务器端的一般处理程序 Handler1.ashx 中的代码:

public void ProcessRequest(HttpContext context)
{
   context.Response.ContentType = "text/event-stream";
   context.Response.Expires = -1;
   while (true)
   {
       context.Response.Write("id:" + DateTime.Now.ToString("yyyyMMddHHmmss") + "\n" + "event:gett" + "\n" + "data:" + DateTime.Now.ToString() + "\n" + "retry:" + 2000 + "\n\n");
       //context.Response.Write("data:" + DateTime.Now.ToString() + "\n" + "retry:" + 2000 + "\n\n");
       context.Response.Flush();
       Thread.Sleep(2000);
   }
}

服务器端约定了 4 个字段:

event 定义事件的名称,如上面的 gett ,可选。

id 定义事件的 ID 字段值,可选。

data 用于传输数据的字段。

retry 重新连接的时间,以毫秒为单位,如果发生错误会等待此时间然后重试,可选。

这些字段的名称后紧跟一个英文冒号 :,然后是其值,字段之间需以一个换行符 \n 分隔,并以两个换行符 \n\n 结尾。

注:如果在线程中不使用循环而直接一次性输出后中断,再配合使用 retry 字段似乎也可以实现相应的功能,但这样每一次都会经过 onopen 和 onerror 事件,并且会重复执行前后端的交互请求,这几乎等同于轮询的方式,所以不推荐这样做。


最后更新时间:2023/08/02 18:08

你一赞赏,我就写得更来劲儿了

注意!你的赞赏转账请考虑再三后支付,此收款不作任何形式的退款。