基于ASP.NET Core api 的服务器事件发送

现如今程序员对Web API的调用已经是轻车熟路。但是传统的api调用都是拉模式,也就是主动发起请求去调用一个api.

但是程序员往往对另一种很有用的模式很陌生,即推模式。

  • 拉模式 - 主动调用并获取结果的模式。

  • 推模式 - 订阅并接受数据推送的模式。

今天要介绍的是一个被大家忽略但却非常有用的一项技术。

基于HTTP/2的标准服务器事件推送模式,英文简称Server-Sent Events,后面简称SSE。

Server-Sent Events

这里引用MDN上的一段解释:

EventSource 是服务器推送的一个网络事件接口。一个EventSource实例会对HTTP服务开启一个持久化的连接,以text/event-stream` 格式发送事件, 会一直保持开启直到被要求关闭。

一旦连接开启,来自服务端传入的消息会以事件的形式分发至你代码中。如果接收消息中有一个事件字段,触发的事件与事件字段的值相同。如果没有事件字段存在,则将触发通用事件。

与 WebSockets,不同的是,服务端推送是单向的。数据信息被单向从服务端到客户端分发. 当不需要以消息形式将数据从客户端发送到服务器时,这使它们成为绝佳的选择。例如,对于处理社交媒体状态更新,新闻提要或将数据传递到客户端存储机制(如IndexedDB或Web存储)之类的,EventSource无疑是一个有效方案。

以上解释简单说明了SSE的用途,该项技术也是推模式的典型技术之一。同类型的技术是WebSockets, 和SignalR。

代码是展示一项技术的最好办法:

SSE客户端实现

//javascript 构造一个EventSource实例,代表一个服务器推送长连接。var source = new EventSource("/api/values"); //传入支持推送模式的api url。随后展示。//当普通消息被传递时触发。source.onmessage = function (event) {console.log('onmessage: ' + event.data);};//当连接打开时触发。source.onopen = function(event) {console.log('onopen');};//当出错时候触发source.onerror = function(event) {console.log('onerror');}//使用自定义时间时候触发。ping为自定义事件,你可以根据实际需求定义自己的事件名称。如果事件名称匹配,则该方法会被调用source.addEventListener("ping", function(event) {console.log('onping' + event.data);});

ASP.NET Core Api 实现

[HttpGet]public async Task GetValue(){//测试,debug到这里的时候你会发现,协议使用的是HTTP/2. APS.NET Core 2.1以上就默认支持HTTP/2,无需额外的配置。再Windows Server2016/Windows10+会自动提供支持。string requestProtocol = HttpContext.Request.Protocol;var response = Response;//响应头部添加text/event-stream,这是HTTP/2协议的一部分。response.Headers.Add("Content-Type", "text/event-stream");for (int i=0;i<100;i++){// event:ping event是事件字段名,冒号后面是事件名称,不要忘了\n换行符。await HttpContext.Response.WriteAsync($"event:ping\n");// data: 是数据字段名称,冒号后面是数据字段内容。注意数据内容仅仅支持UTF-8,不支持二进制格式。// data后面的数据当然可以传递JSON String的。await HttpContext.Response.WriteAsync($"data:Controller {i} at {DateTime.Now}\r\r");// 写入数据到响应后不要忘记 FlushAsync(),因为该api方法是异步的,所以要全程异步,调用同步方法会报错。await HttpContext.Response.Body.FlushAsync();//模拟一个1秒的延迟。await Task.Delay(1000);}//数据发送完毕后关闭连接。Response.Body.Close();}

协议的字段解释(来源MDN)

event

事件类型.如果指定了该字段,则在客户端接收到该条消息时,会在当前的EventSource对象上触发一个事件,事件类型就是该字段的字段值,你可以使用addEventListener()方法在当前EventSource对象上监听任意类型的命名事件,如果该条消息没有event字段,则会触发onmessage属性上的事件处理函数.

data

消息的数据字段.如果该条消息包含多个data字段,则客户端会用换行符把它们连接成一个字符串来作为字段值.

id

事件ID,会成为当前EventSource对象的内部属性"最后一个事件ID"的属性值.

retry

一个整数值,指定了重新连接的时间(单位为毫秒),如果该字段值不是整数,则会被忽略.

消息的例子:

event: userconnect
data: {"username": "bobby", "time": "02:33:48"}event: usermessage
data: {"username": "bobby", "time": "02:34:11", "text": "Hi everyone."}event: userdisconnect
data: {"username": "bobby", "time": "02:34:23"}event: usermessage
data: {"username": "sean", "time": "02:34:36", "text": "Bye, bobby."}

这里提醒大家去仔细阅读消息的格式。消息格式错误,将导致数据无法正确解析。

实现效果

b98fa76333e7f636c25886f8ff74fd30.png

看到类型为eventsource

5c81cefc7590d31875f98c4e91b5796e.png

看到事件类型为ping,每个一秒数据被推送到客户端一次

33b867d84f0ef5f5b227a4431f3aa08a.png

长连接,请求一直未完成。

Server-Sent Events vs WebSockets

到这里大家不难发现SSE技术其实也是一种实时服务端推送数据的技术,但是他的光环被更为闪耀的WebSockets给覆盖了。Stackoverflow上有一篇很不错的对比。大家可以搜索WebSockets vs. Server-Sent events/EventSource

总的来说,SSE能实现的功能WebSockets都能实现,但是SEE更轻量无需其他库并且服务器端也非常容易编写。同时她是基于HTTP的,自然在穿透防火墙方面也就无需太多顾虑。更多的对比结论如下(参考。

SSE 相对于 Websockets 的优势:

  • 通过简单的 HTTP 而不是自定义协议传输

  • 可以使用第三方库支持不支持SSE的浏览器例如IE浏览器。

  • 内置支持重新连接和事件 ID

  • 更简单的协议

  • 企业防火墙进行数据包检查不会有问题。

Websockets 相对于 SSE 的优势:

  • 实时,双向通信。

  • 更多浏览器的原生支持

SSE 的理想用例:

  • 股票行情流,数据监控大屏数据发送,IOT物联网设备数据发送。

  • 社交平台上的状态更新等。

  • 浏览器通知

SSE缺陷:

  • 不支持二进制

  • 最大打开连接数限制。HTTP1.1 单个浏览器只支持6个连接(也就是打开6个Tab页以上就会出问题,并且在Chrom和Firefox上无法解决)HTTP/2上默认100个。

总结

SSE是一项轻量级的基于HTTP/2的标准协议,除了IE浏览器(不包含Edge)以外的其他浏览器均已支持该协议。后端服务ASP.NET Core 无疑也是完美支持的,.NET程序员可以放心使用。因为SSE使用HTTP最大的优势可以避过防火墙的坑,WebSockets协议在穿透防火墙时候可能会有问题,而且有些老式的中间设备可能不认识WebSockets协议导致兼容性问题。

SSE另一个优点是无需额外的库就可以启用,而且支持自动重连。非常适合从服务器推送数据到客户端的单项应用。而不用无脑的考虑WebSockets协议。甚至可以吧SSE 和 Websokets协议联合起来使用,当仅需服务器单项传输时候采用SSE,需要双向传输时候采用Websokets.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/291185.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android之解决java.lang.NoSuchMethodError:android.os.powerManager.isInteractive问题

1、问题 再三星平板(Android 4.2.2系统)我们代码powerManager调用了函数isInteractive方法,出现下面错误 java.lang.NoSuchMethodError:android.os.powerManager.isInteractive 2、解决办法 1、一开始想用try catch来解决,肯定不行,功能没实现,而且进程还是会挂 2…

DDD为何叫好不叫座?兼论DCI与业务分析的方法论

今天&#xff0c;仔细阅读了园子里面的一个朋友写的《一缕阳光&#xff1a;DDD&#xff08;领域驱动设计&#xff09;应对具体业务场景&#xff0c;如何聚焦 Domain Model&#xff08;领域模型&#xff09;&#xff1f;》(http://www.cnblogs.com/xishuai/p/3800656.html)这篇博…

php 实现的字典序排列算法,字典序的一个生成算法

字典序的一个生成算法。最近在LeetCode刷题&#xff0c;刷到一个题&#xff0c;链接&#xff1a;https://leetcode-cn.com/problems/permutation-sequence/这个题要求得长度为n的字典序列的第k个排列。我们知道&#xff0c;字典序列是一个长度为n(n>1)&#xff0c;元素为1~n…

BeetleX服务网关流量控制

为了保障后台服务应用更可靠地运行&#xff0c;网关提供了一些基础流量控制功能&#xff1b;通过这一功能可以限制流转到后台应用服务的处理量&#xff0c;从而让服务在可应对的并发范围内更可靠地运作。服务网关提供了流量控制有基础控制、IP、域名和请求路径。基础配置主要包…

【cocos2d-x】2.0升级为3.0一些常见变化纪录

1.去CC之前2.0的CC**,把CC都去掉&#xff0c;基本的元素都是保留的2.0CCSprite CCCallFunc CCNode ..3.0Sprite CallFunc Node ..2.cc***结构体改变2.0 ccp(x,y) ccpAdd(p1,p2)ccpSubccpMultccpLength(p)ccpDot(p1,p2);ccc3()ccc4()ccWHITECCPointZeroCCSizeZer…

Java Web开发——Servlet监听器

一、Servlet监听器的概念 Servlet监听器是Servlet规范中定义的一种特殊类&#xff0c;用于监听ServletContext、HttpSession和ServletRequest等域对象的创建与销毁事件&#xff0c;以及监听这些域对象中属性发生修改的事件。 监听对象&#xff1a; 1、ServletContext&#xff1…

通过Dapr实现一个简单的基于.net的微服务电商系统(十九)——分布式事务之Saga模式...

目录&#xff1a;一、通过Dapr实现一个简单的基于.net的微服务电商系统二、通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解三、通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr四、通过Dapr实现一个简单的基于.net的微服…

php怎么关闭oracle连接,PHP 连接 Oracle

起因由于项目的数据库需要用客户购买的Oracle数据库&#xff0c;所以需要php安装oci扩展。运行环境php : 7.2系统: windows10oracle: 11gR2安装相关环境由于php的oci8扩展还是需要使用到oracle的一些包&#xff0c;所以先下载这一些。下载完成后解压缩这个压缩包&#xff0c;并…

.NET 深度指南:Colors

作者 &#xff5c; Peter Huber译者 &#xff5c; 王强策划 &#xff5c; 丁晓昀我不知道你们是什么情况&#xff0c;但我自己在过去多年中都因为.NET 色彩&#xff08;Colors&#xff09;类中可用的色彩数量有限而头痛不已&#xff0c;为此我试图用 ColorPickers 获得匹配的色…

php 怎么打出来的,word书名号怎么打出来

书名号怎么打出来&#xff1f;书名号相信大家都不会陌生了&#xff0c;正常情况下&#xff0c;我们会将书名、歌曲名、作品名等用书名号框起来&#xff0c;这样就可以让读者一目了然。然而很多用户在编辑Word和Excel文档时&#xff0c;想输入书名号却不知从何下手&#xff0c;这…

springMVC带文件的表单数据无法绑定到参数中

2019独角兽企业重金招聘Python工程师标准>>> 在一个带enctype"multipart/form-data"属性的表单提交时发现&#xff0c;该表单中包含的其他input无法设置到对应方法参数中。 如下&#xff1a; JSP&#xff1a;带enctype"multipart/form-data"属性…

关于Retinex图像增强算法的一些新学习。

最近再次看了一下IPOL网站&#xff0c;有一篇最近发表的文章&#xff0c;名字就是Multiscale Retinex&#xff0c;感觉自己对这个已经基本了解了&#xff0c;但还是进去看了看&#xff0c;也有一些收获&#xff0c;于是抽空把他们稍微整理了下&#xff0c;原始文章及其配套代码…

如何判断 .NET Core 应用程序是以管理员身份运行

有时候&#xff0c;我们需要知道当前程序是否以管理员身份运行&#xff0c;以便执行一些需要特殊权限的操作。在github(https://github.com/dotnet/runtime/issues/25118#issuecomment-367407469)上找到了一个解决方案&#xff1a;//需要引用nuget包Mono.Posix.NETStandard pub…

Android之Content和activity、service、Application关系和attachBaseContext函数调用的时候

1、Content和activity、service、Application关系 2、Application里面attachBaseContext和onCreate函数调用顺序 Application-> attachBaseContext ();ContentProvider:onCreate()Application:onCreate()人还是容易忘记&#xff0c;先记录下来。

批量创建域账号

创建5列的csv文档&#xff08;注意文件编码&#xff09; 执行如下脚本 for /f "tokens1,2,3,4,5 delims," %a in (c:\test.csv) do dsadd user "cn%c,oumk,ouicgroup,dcicdomain,dccom" -samid %d -upn %dicdomain.com -ln %a -fn %b -pwd %e -disabled no…

如何快速编写并运行Tiny模板语言?

2019独角兽企业重金招聘Python工程师标准>>> 说到模板开发&#xff0c;当然就离不开要调试&#xff0c;要运行。 由于一般情况下模板语言都是由Java程序驱动跑的&#xff0c;因此&#xff0c;每次都需要搞一个Java类来驱动它&#xff0c;才能运行出结果。这个对于悠…

Windows 11 上大招!正式支持安卓!

面向 Windows 11 正式版用户&#xff0c;微软现已发布累积更新 KB5010414&#xff0c;更新后版本号升级至 Build 22000.527。KB5010414 是一个可选更新&#xff0c;因此除非您主动点击“获取更新”按钮&#xff0c;否则它不会下载或安装。该更新将于 2022 年 3 月向所有 Window…

博客流量分析

接连两篇Spark内核分析的文章都被推荐到CSDN首页&#xff0c;带来的流量还是很客观的&#xff0c;基本上一天最少500个独立IP的访问。这个访问量还是很客观的&#xff0c;比推荐到博客首页和侧边栏还是效果好处不少的。88%的流量来自首页。北京不愧是码农的聚集地啊&#xff0c…

WPF 基础控件之CheckBox样式

WPF开发者QQ群&#xff1a;340500857由于微信群人数太多入群请添加小编微信号yanjinhuawechat 或 W_Feng_aiQ 邀请入群需备注WPF开发者 PS&#xff1a;有更好的方式欢迎推荐。支持NugetInstall-Package WPFDevelopers.Minimal -Version 3.0.001—代码如下一、创建 Styles.Check…

Theano3.2-练习之数据集及目标函数介绍

来自http://deeplearning.net/tutorial/gettingstarted.html#gettingstarted 一、下载 在后续的每个学习算法上&#xff0c;都需要下载对应的文档&#xff0c;如果想要一次全部下好&#xff0c;那么可以复制git上面的这个教程的资料&#xff1a; git clone git://github.com/li…