微信公眾號:趣編程ACE
關注可了解更多的.NET日常開發技巧,如需源碼 請公眾號留言 源碼;
如果覺得本公眾號對你有幫助,歡迎關注
【SignalR全套系列】之在.Net Core 中實現Server-Send Events消息推送
1.前文鏈接:
【SignalR全套系列】之在.NetCore中實現WebSocket雙工通信
2.簡介:
嚴格來說,HTTP協議無法做到服務器主動推送消息,有一種變通方法就是,服務器告知客戶端我接下里要發送的是流信息,而SSE(Server-Send Events)就是基于這個原理來實現通信的。
SSE與WebSocket作用類似,都是作用于服務端與客戶端之間通信的,但是Websocket 是全雙工通信,而SSE只能是單工通信(服務器向瀏覽器發送)
具體講解可參考下面文章:
https://www.ruanyifeng.com/blog/2017/05/server-sent_events.html
3.基于.Net Core 實現SSE
首先建立一個客戶端頁面程序:
1<!DOCTYPE?html>2<html>3<head>4????<meta?charset="utf-8"?/>5????<title></title>6</head>7<body>8????<script>9????????var?source?=?new?EventSource("/see");??//SSE?API對象
10????????//?onmessage?是用來接受消息的通用回調函數
11????????source.onmessage?=?(event)?=>?console.log('接收服務端消息',?event.data);
12????????//?onopen?當服務端與客戶端建立鏈接后?就會觸發open?事件
13????????source.onopen?=?()?=>?console.log("開始鏈接");
14????????//?通信失敗?就會觸發?error事件??這時候回調onerror函數
15????????source.onerror?=?(event)?=>?console.log(event);
16
17????????//?自定義事件?可以自定義需要執行的message事件??這時候通用的message事件就不會被觸發了
18????????source.addEventListener('custom',?(e)?=>?console.log('custom',?e.data));
19????</script>
20</body>
21</html>
服務端應用程序:
1public?class?Startup2????{34????????private?readonly?Channel<string>?_channel;?//?通道變量5????????public?Startup(IConfiguration?configuration)6????????{7????????????Configuration?=?configuration;8????????????_channel?=?Channel.CreateUnbounded<string>();?//?創建一個無消息上限的通道9????????}
10
11????????public?IConfiguration?Configuration?{?get;?}
12
13????????//?This?method?gets?called?by?the?runtime.?Use?this?method?to?add?services?to?the?container.
14????????public?void?ConfigureServices(IServiceCollection?services)
15????????{
16????????????services.AddControllers();
17????????}
18
19????????//?This?method?gets?called?by?the?runtime.?Use?this?method?to?configure?the?HTTP?request?pipeline.
20????????public?void?Configure(IApplicationBuilder?app,?IWebHostEnvironment?env)
21????????{
22????????????if?(env.IsDevelopment())
23????????????{
24????????????????app.UseDeveloperExceptionPage();
25????????????}
26
27????????????//?開啟靜態文件
28????????????app.UseStaticFiles();
29
30????????????app.UseRouting();
31
32????????????app.UseAuthorization();
33
34????????????app.UseEndpoints(endpoints?=>
35????????????{
36????????????????endpoints.MapControllers();
37????????????????//?捕獲路由??/send?m=xxxxx
38????????????????endpoints.Map("/send",?async?ctx?=>
39????????????????{
40????????????????????if?(ctx.Request.Query.TryGetValue("m",?out?var?m))
41????????????????????{
42????????????????????????//?控制臺輸出
43????????????????????????Trace.WriteLine("開始發送?:"?+?m);
44????????????????????????//??寫入到通道中去
45????????????????????????await?_channel.Writer.WriteAsync(m);
46????????????????????}
47????????????????????//?響應返回
48????????????????????ctx.Response.StatusCode?=?200;??
49????????????????});
50????????????});
51
52????????????//?自定義一個中間件
53????????????app.Use(async?(ctx,?next)?=>
54????????????{
55????????????????//?發送?/see?路由??建立鏈接
56????????????????if(ctx.Request.Path.ToString().Equals("/see"))
57????????????????{
58????????????????????var?response?=?ctx.Response;
59????????????????????//?以流的形式?返回給客戶端?
60????????????????????response.Headers.Add("Content-Type",?"text/event-stream");
61
62????????????????????//??返回響應信息??
63????????????????????await?response.WriteAsync("event:custom\r");
64????????????????????await?response.WriteAsync("data:自定義事件消息\r\r");
65
66????????????????????while(await?_channel.Reader.WaitToReadAsync())
67????????????????????{
68????????????????????????var?message?=?await?_channel.Reader.ReadAsync();
69????????????????????????Trace.WriteLine("捕捉發送消息:"+message);
70????????????????????????await?response.WriteAsync($"data:{message}\r\r");
71
72????????????????????????await?response.Body.FlushAsync();
73????????????????????}
74????????????????}
75????????????});
76????????}
77????}