flux服务器推消息,服务端主动推送数据,除了 WebSocket 你还能想到啥?
原标题:服务端主动推送数据,除了 WebSocket 你还能想到啥?
来自公众号: 江南一点雨
在 上篇文章 中,松哥和大家分享了 WebFlux 的基本用法,小伙伴们已经了解到使用 WebFlux 我们的返回值可以是 Mono 也可以是 Flux,如果是 Flux,由于 Flux 中包含多个元素,所以我们需要设置响应的 Content-Type 为 text/event-stream 。考虑到很多小伙伴还没用过 text/event-stream ,所以今天松哥再撸一篇文章来和大家聊聊 text/event-stream 。
1.SSE
首先我们来看一个概念叫做 SSE。
SSE 全称是 Server-Sent Events,它的作用和 WebSocket 的作用相似,都是建立浏览器与服务器之间的通信渠道,然后服务器向浏览器推送信息,不同的是,WebSocket 是一种全双工通信协议,而 SSE 则是一种单工通信协议,即使用 SSE 只能服务器向浏览器推送信息流,浏览器如果向服务器发送信息,就是一个普通的 HTTP 请求。
使用 SSE,当服务端给客户端响应的时候,他不是发送一个一次性数据包,而是会发送一个数据流,这个时候客户端的连接不会关闭,会一直等待服务端发送过来的数据流,我们常见的视频播放其实就是这样的例子。
SSE 和 WebSocket 主要有如下区别:
SSE 使用 HTTP 协议,现有的服务器软件都支持。WebSocket 是一个独立协议。
SSE 属于轻量级,使用简单;WebSocket 协议相对复杂。
SSE 默认支持断线重连,WebSocket 需要自己实现。
SSE 一般只用来传送文本,二进制数据需要编码后传送,WebSocket 默认支持传送二进制数据。
SSE 支持自定义发送的消息类型。
说了这么多,可能大家还是有点懵,接下来松哥通过一个简单的例子来向大家展示 SSE 的用法。
2.开发服务端
根据第一小节的描述,大家也能看出来,SSE 其实和框架没有关系,所以这里松哥就创建一个普通的 Java Web 项目,用最最基本的 Servlet 来向大家演示 SSE 的功能。
首先我们创建一个 SseServlet,内容如下:
@WebServlet(urlPatterns = "/sse")
publicclassSseServletextendsHttpServlet{
@Override
protectedvoiddoGet(HttpServletRequest req, HttpServletResponse resp)throwsServletException, IOException{
doPost(req,resp);
}
@Override
protectedvoiddoPost(HttpServletRequest req, HttpServletResponse resp)throwsServletException, IOException{
resp.setContentType( "text/event-stream;charset=utf-8");
PrintWriter out = resp.getWriter;
for( inti = 0; i < 10; i++) {
out.write( "data: 江南一点雨:"+ i+ "\n\n");
out.flush;
try{
Thread.sleep( 1000);
} catch(InterruptedException e) {
e.printStackTrace;
}
}
}
}
往出写 10 条数据,每写一条就睡眠 1 秒钟。代码并不难,但是这里有几个细节需要注意下:
响应的 Content-Type 记得设置为 text/event-stream ,这是关键。
每一次发送的信息,由若干个 message 组成,每个 message 之间用 \n\n 分隔,每个 message 内部由若干行组成。在上面的案例中,每一个 for 循环中就是发送一个 message。
每一行的数据格式是 : [field]: value\n 。field 有四种不同取值:data:data 用来表示数据内容,就像我们上面的例子。
id:id 相当于是每一条数据的唯一编号,浏览器用 lastEventId 属性读取这个值。一旦连接断线,浏览器会发送一个 HTTP 头,里面包含一个特殊的 Last-Event-ID 头信息,将这个值发送回来,用来帮助服务器端重建连接。因此,这个头信息可以被视为一种同步机制。
event: event 字段表示自定义的事件类型,默认是 message 事件。
retry:服务器可以用 retry 字段,指定浏览器重新发起连接的时间间隔。
开发完成后,我们启动服务端访问 /sse 接口来看看效果:
可以看到,客户端每隔 1 秒就能收到服务端的数据。
3.开发客户端
前面是一个服务端的案例,接下来我们来看看客户端的案例,新建一个 html 页面,添加如下 js:
vares = newEventSource( "/sse");
es.onopen = function( e){
console.log( "open")
};
es.onmessage = function( e){
console.log(e.data);
}
es. = function( e){
console.log( "error")
es.close
}
关于上面这段代码:
首先新建一个 EventSource 对象,参数就是服务端的地址。它还有一个可选的参数,可选参数重可以描述是否将 Cookie 一起发送出去 var es = new EventSource("/es", { withCredentials: true }); (可在跨域时使用该参数)。
当建立连接后,就会触发 onopen 函数,当收到服务端发送来的消息,就会触发 onmessage 函数,当连接出错的时候,就会触发 函数。
es.close 表示关闭 SSE 连接。
这三种类型的事件,我们还可以通过如下方式来定义:
vares = newEventSource( "/sse");
es.addEventListener( "open", function( e){
console.log( "open");
})
es.addEventListener( "message", function( e){
console.log(e.data);
})
es.addEventListener( "error", function( e){
console.log( "error")
es.close;
})
效果与上面的一致,我们来看看运行效果图:
消息接收完后,会触发 事件,此时我们可以关闭 SSE 连接, 否则就会从头开始继续接收数据。
4.自定义事件
我们也可以自定义 SSE 事件。
先来看服务端如何自定义:
@WebServlet(urlPatterns = "/sse")
publicclassSseServletextendsHttpServlet{
@Override
protectedvoiddoGet(HttpServletRequest req, HttpServletResponse resp)throwsServletException, IOException{
doPost(req, resp);
}
@Override
protectedvoiddoPost(HttpServletRequest req, HttpServletResponse resp)throwsServletException, IOException{
resp.setContentType( "text/event-stream;charset=utf-8");
PrintWriter out = resp.getWriter;
for( inti = 0; i < 10; i++) {
out.write( "event:javaboy\n");
out.write( "data: 江南一点雨:"+ i + "\n\n");
out.flush;
try{
Thread.sleep( 1000);
} catch(InterruptedException e) {
e.printStackTrace;
}
}
}
}
如上,在每一行消息之前添加 out.write("event:javaboy\n"); 表示自定义事件类型,当然我们也可以添加事件 id,方式如下:
@WebServlet(urlPatterns = "/sse")
publicclassSseServletextendsHttpServlet{
@Override
protectedvoiddoGet(HttpServletRequest req, HttpServletResponse resp)throwsServletException, IOException{
doPost(req, resp);
}
@Override
protectedvoiddoPost(HttpServletRequest req, HttpServletResponse resp)throwsServletException, IOException{
resp.setContentType( "text/event-stream;charset=utf-8");
PrintWriter out = resp.getWriter;
for( inti = 0; i < 10; i++) {
out.write( "event:javaboy\n");
out.write( "id:"+ i + "\n");
out.write( "data: 江南一点雨:"+ i + "\n\n");
out.flush;
try{
Thread.sleep( 1000);
} catch(InterruptedException e) {
e.printStackTrace;
}
}
}
}
服务端定义完成后,接下来我们再来看看前端该如何接收数据:
vares = newEventSource( "/sse");
es.addEventListener( "open", function( e){
console.log( "open");
})
es.addEventListener( "javaboy", function( e){
console.log(e.data, e.lastEventId, e);
})
es.addEventListener( "error", function( e){
console.log( "error")
es.close;
})
此时在 addEventListener 方法中,输入自定义的事件名称,然后在回调函数中处理事件。
可以通过 e.lastEventId 访问到消息的 id。
5.小结
好啦,今天主要通过几个简单的例子向大家展示 text/event-stream 以及 SSE 相关的知识点,相信大家在学完之后对 WebFlux 中返回值为 Flux 的接口会有更深的理解,读完本文,再去看昨天的文章【 WebFlux 初体验 】,应该会更香。
参考资料:http://www.ruanyifeng.com/blog/2017/05/server-sent_events.html
--- EOF ---
责任编辑:
flux服务器推消息,服务端主动推送数据,除了 WebSocket 你还能想到啥?相关推荐
- 使用SignalR从服务端主动推送警报日志到各种终端(桌面、移动、网页)
工作上有个业务,.Net Core WebAPI作为服务端,需要将运行过程中产生的日志分类,并实时推送到各种终端进行报警,终端有桌面(WPF).移动(Xamarin.Forms).网站(Angular ...
- 服务端主动推送数据,除了 WebSocket 你还能想到啥?
在上篇文章中,松哥和大家分享了 WebFlux 的基本用法,小伙伴们已经了解到使用 WebFlux 我们的返回值可以是 Mono 也可以是 Flux,如果是 Flux,由于 Flux 中包含多个元素, ...
- spring集成mina,包含心跳检测,实现服务端主动推送
服务端 1.常规的spring工程集成mina时,pom.xml中需要加入如下配置: <dependency><groupId>org.slf4j</groupId> ...
- Netty-Server-Hander自定义解码器-服务端主动推送
netty server端使用自定义解码器,通过存储client连接实现主动推送消息,并发送自定义心跳包 Server端 依赖 <dependency><groupId>io. ...
- 利用mochiweb让服务端主动推送数据至前端页面
对于智能化监控软件,从wincc等国外的有相当积累的系统,以及国内一些小型的智能化集成软件,通常其监控数据通过前端绑定控件的方式,做到了实时的通讯,通过控件直接和后端服务交互.这种方式可以灵活的组态, ...
- 服务端如何推送消息给客户端?
大家好,我是前端西瓜哥,今天带大家了解一下服务端如何推送消息给客户端. 有时候,我们希望服务端能够主动推送一些信息给客户端.但 HTTP 协议只能让客户端发起请求然后服务端响应,而无法让服务端主动去发 ...
- http协议与https协议+UDP协议和TCP协议+WebSocket协议下服务端主动去发送信息+对称加密与非对称加密+get和post请求方式区别详解+浏览器内核以及jsj解析引擎
TCP和UDP协议是TCP/IP协议的核心. 在TCP/IP网络体系结构中,TCP(传输控制协议,Transport Control Protocol).UDP(用户数据报协议,User Data P ...
- springboot实现SSE服务端主动向客户端推送数据,java服务端向客户端推送数据,kotlin模拟客户端向服务端推送数据
SSE服务端推送 服务器向浏览器推送信息,除了 WebSocket,还有一种方法:Server-Sent Events(以下简称 SSE).本文介绍它的用法. 在很多业务场景中,会涉及到服务端向客户端 ...
- 例子 客户端_服务端也是可以主动向客户端推送数据的--WebSocket
简介 WebSocket是一种在单个TCP连接上进行全双工通信的协议.WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范.WebSocket API也 ...
最新文章
- android StringBuilder的Capacity的使用
- pytorch 使用DataParallel 单机多卡和单卡保存和加载模型时遇到的问题
- php分布式缓存系统 Memcached 入门
- 计算机创建文档教案,计算机基础知识教案
- 一些不错的网站界面收藏
- MariaDB-5.5.56 主主复制+keepalived高可用
- 软件工程导论 05章总体设计
- React的单向数据流与组件间的沟通
- Docker详解(十一)——Docker容器CPU资源限额实战
- matlab全局变量_MATLAB笔记(一):工具箱的卸载、阻尼振动波形图程序
- Logstash_snmp与Logstash_snmptrap日志采集配置说明
- 三分钟介绍什么是前端开发框架
- PowerShadow Master(影子系统)
- 十个拿来就能用的网页炫酷特效
- java的listroots_Java File listRoots()用法及代码示例
- java语言之面向对象
- HTML邮件制作心得
- 亚洲首台BMD8K切换台开箱
- 实体间的联系存在着( )_医药零售的网络销售与实体渠道如何协同
- 苹果手机咋截屏_苹果手机信号满格但是没网络咋处理
热门文章
- 今晚7点30,腾讯专家与你共探广告智能创意新可能
- js 获取中括号里面字符串_西门子SCL编程入门教程连载(18)——字符串
- 召回离线评估指标(二)
- 工程数学(数值分析)第六讲:数值微积分
- Tensorflow笔记(一): tensorflow的安装
- Clob 2 String
- SpringBoot App Registers UNKNOWN with Eureka in Brixton SR3
- Android native音频:录制播放的实现以及低延迟音频方案
- oracle-j2sdk1.8,CDH agent无法安装
- 说透Applet的数字签名之2——数字签名