赞
踩
提到服务端数据推送,你可以一下子就想到了Websocket,WebSocket是一种全新的协议,随着HTML5草案的不断完善,越来越多的现代浏览器开始全面支持WebSocket技术了,它将TCP的Socket(套接字)应用在了webpage上,从而使通信双方建立起一个保持在活动状态连接通道。
但你可能不知道,HTML5中有一个轻量的替代Websocket的方案:SSE(Server-Sent Events)。
WebSocket 和 SSE 都是传统请求-响应 Web 架构的替代方案,但它们不是完全冲突的技术。
首发地址:https://www.pomit.cn/p/3795471065500161
几乎所有现代浏览器都支持 WebSocket 协议,包括移动浏览器。然而Microsoft IE 和 Edge不支持SSE
但这并不妨碍我们使用SSE,毕竟用IE的人还有几个呢?如果是内部使用,为什么不使用更简单的SSE呢?
本篇不讲websocket,有兴趣的可以阅读SpringBoot入门建站全系列(二十七)WebSocket做简单的聊天室了解更多关于websocket的使用。
这里讲述如何使用SSE建立服务端的推送。
如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以加入我们的java学习圈,点击即可加入,共同学习,节约学习时间,减少很多在学习中遇到的难题。
这里我们使用聊天来模拟SSE的数据推送。我这里写了几个自定义的对象
在Springboot项目中使用SSE,是不需要额外引入依赖的,只需要把spring-boot-starter-web引入即可。也不需要额外的配置。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
要使用SSE,首先需要定义一个维持SSE长连接的接口地址,就像websocket中定义websocket的端口地址一样,但是SSE这里和普通的http没有多大区别,只是响应头是text/event-stream
.
示例:
@GetMapping(value = "/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter to(HttpServletRequest request) {
String userName = (String) request.getSession().getAttribute("userName");
// 超时时间设置为3分钟
SseEmitter sseEmitter = new SseEmitter(180000L);
Chater chater = WebSSEUser.getChater(userName);
sseEmitter.onTimeout(() -> chater.setSseEmitter(null));
sseEmitter.onCompletion(() -> System.out.println("完成!!!"));
chater.setSseEmitter(sseEmitter);
return sseEmitter;
}
这里是Springboot应用中使用SSE,我定义了/subscribe
接口:
text/event-stream
SSE调用/subscribe
接口接口以后,会一直使用一个请求,类似websocket。
上面的代码只是保持了长连接,而且是单向的,只能是服务端给客户端发消息。
单向的意思就是,客户端不能通过SSE去发送消息,服务端可以通过SSE给客户端发送消息。
但是我们还是可以使用SSE来完成聊天功能的,因为客户端可以通过普通http请求去发送消息,到服务端以后再发送给其他客户端。
示例:
@RequestMapping(value = "/send") public ResultModel send(@RequestBody MessageDTO<String> messageDTO, HttpServletRequest request) { logger.info("收到发往用户[{}]的文本请求;", messageDTO.getTargetUserName()); Object userName = request.getSession().getAttribute("userName"); if (userName == null) return ResultModel.error("无用户"); messageDTO.setFromUserName((String) userName); messageDTO.setMessageType(Type.TYPE_TEXT.getMessageType()); Chater chater = WebSSEUser.getChater(messageDTO.getTargetUserName()); try { chater.getSseEmitter().send(messageDTO); } catch (IOException e) { e.printStackTrace(); } return ResultModel.ok(); }
这里,通过目标的userName获取到Chater对象,然后Chater对象中保存有SseEmitter对象,SseEmitter对象可以直接发送消息到客户端。
前面讲述了服务端维持SSE的方法。下面讲述下客户端如何操作。
调用服务端的/subscribe
接口,维持长连接,请阅服务端消息。
var url = "/subscribe";
var es = new EventSource(url);
es.addEventListener("message", function(e){
decode(e);
},false);
不需要额外引入js,addEventListener中可以调用其他方法对消息解析并操作。
这里的decode(e);
是对应服务端的chater.getSseEmitter().send(messageDTO);
普通的ajax请求即可,无需额外处理,调用服务端的/send
接口即可。
如图:
/subscribe
接口,这个连接会一直持续下去,图上已经持续了十几秒。/send
接口,发送消息给服务端,服务端转发给其他客户端。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。