SSE(Server-Send Events)实践
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SSE(Server-Send Events)实践相关的知识,希望对你有一定的参考价值。
参考技术AHTTP 是客户端-服务器计算模型中的请求-响应协议。要开始交换,客户端向服务器提交请求。为了完成交换,服务器向客户端返回响应。服务器只能向一个客户端发送响应 (发出请求的那个) 。在 HTTP 协议中,客户端是消息交换的发起者。
服务器发送事件 (SSE) 是一种简单的技术,用于为特定的 Web 应用程序实现服务器到客户端的异步通信。
有多种技术允许客户端从服务器接收有关异步更新的消息。它们可以分为两类: 客户端拉取 和 服务器推送 。
在客户端拉取技术中,客户端会定期向服务器请求更新。服务器可以使用更新或尚未更新的特殊响应进行响应。有两种类型的客户端拉取:短轮询和长轮询。
客户端定期向服务器发送请求。如果服务器有更新,它会向客户端发送响应并关闭连接。如果服务器没有更新,它也会向客户端发送一个响应并关闭连接。
客户端向服务器发送请求。如果服务器有更新,它会向客户端发送响应并关闭连接。如果服务器没有更新,它会保持连接直到更新可用。当更新可用时,服务器向客户端发送响应并关闭连接。如果更新在某个超时时间内不可用,服务器会向客户端发送响应并关闭连接。
在服务器推送技术中,服务器在消息可用后立即主动向客户端发送消息。其中,有两种类型的服务器推送:SSE和 WebSocket。
SSE 是一种在基于浏览器的 Web 应用程序中仅从服务器向客户端发送文本消息的技术。SSE基于 HTTP 协议中的持久连接, 具有由 W3C 标准化的网络协议和 EventSource 客户端接口,作为 html5 标准套件的一部分。
WebSocket 是一种在 Web 应用程序中实现同时、双向、实时通信的技术。WebSocket 基于 HTTP 以外的协议(TCP),因此可能需要额外设置网络基础设施(代理服务器、NAT、防火墙等)。
客户端通过Http协议请求,在握手阶段升级为WebSocket协议。
在数据字段中,服务器可以发送事件数据
服务器可以发送唯一的事件标识符(id字段)。如果连接中断,客户端会 自动重新连接 并发送最后接收到的带有header的 Last-Event-ID 的事件 ID。
在重试字段中,服务器可以发送超时(以毫秒为单位),之后客户端应在连接中断时自动重新连接。如果未指定此字段,则标准应为 3000 毫秒。
如果一行以冒号字符 : 开头,客户端应该忽略它。这可用于从服务器发送评论或防止某些代理服务器因超时关闭连接。
要打开连接,应创建一个 EventSource 对象。
尽管 SSE 旨在将事件从服务器发送到客户端,但可以使用 GET 查询参数将数据从客户端传递到服务器。
要关闭连接,应调用方法 close()。
有表示连接状态的 readyState 属性:
客户端接收消息并处理他们,可以使用onmessage方法
SSE可被大多数浏览器支持:
Spring Web MVC 框架 5.2.0 是基于 Servlet 3.1 API 且用线程池实现异步应用程序. 所以应用能够被使用在 Servlet 3.1+ 的容器,比如:Tomcat 8.5 和 Jetty 9.3.
使用Spring MVC来发送事件:
示例:
在这个例子中,服务器每秒发送一个持续时间短的周期性事件流 - 一个有限的词流,直到词完成。
示例:
运行效果:
客户端示例(words.html):
运行效果:
在此示例中,服务器发送持久的周期性事件流 - 每秒可能无限的服务器性能信息流:
效果预览(每秒输出一次):
非周期性是指没有固定的时间周期,可能由其他因素在任意时刻都可能触发,下面示例通过spring event来模拟触发因子。
效果:
模拟触发动作:调用 http://localhost:8080/sse/mvc/trigger?eventType=customer
客户端收到数据:
Spring Web Flux 框架 5.2.0 是基于 Reactive Streams API 且使用 event-loop 计算模型来实现异步java应用程序。 此类应用程序可以在非阻塞 Web 服务器(例如 Netty 4.1 和 Undertow 1.4)和 Servlet 3.1+ 容器(例如 Tomcat 8.5 和 Jetty 9.3)上运行。
使用 Spring Web Flux 框架实现发送事件:
简单示例:
和上面spring mvc的示例一样,也是每秒输出数据,实现如下:
效果:
对比spring mvc的实现,我们改为flux实现,如下:
效果和上面是一样的,可以看出,reactive api是非常的简洁。
SignalR全套系列之在.Net Core 中实现Server-Send Events消息推送
微信公众号:趣编程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 Startup
2
3
4 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
以上是关于SSE(Server-Send Events)实践的主要内容,如果未能解决你的问题,请参考以下文章
SignalR全套系列之在.Net Core 中实现Server-Send Events消息推送
服务器推送浏览器:Server-Sent Events(SSE)
SSE(Server-Sent Events):替代websocket完成服务器推送
Websocket、Server Sent Events (SSE) 和 HTTP2 的 Server Pushing 有啥区别?