Spring Boot中使用SSE(Server-Sent Events)实现聊天功能:替代websocket服务器推送

 更新时间:2026年03月14日 08:54:08   作者:weixin_39659837  
本文讲解了如何在Spring Boot项目中使用SSE实现聊天功能,SSE适用于客户端只需要接收更新的应用场景,而WebSocket则适合全双工通信,客户端通过服务端的/subscribe接口维持长连接,服务端通过SseEmitter对象发送消息

一、概述

提到服务端数据推送,你可以一下子就想到了Websocket,WebSocket是一种全新的协议,随着HTML5草案的不断完善,越来越多的现代浏览器开始全面支持WebSocket技术了,它将TCP的Socket(套接字)应用在了webpage上,从而使通信双方建立起一个保持在活动状态连接通道。

但你可能不知道,HTML5中有一个轻量的替代Websocket的方案:SSE(Server-Sent Events)。

WebSocket 和 SSE 都是传统请求-响应 Web 架构的替代方案,但它们不是完全冲突的技术。 - WebSocket 架构在客户端与服务器之间打开一个套接字,用于实现全双工(双向)通信。 无需发送 GET 消息并等待服务器响应,客户端只需监听该套接字,接收服务器更新,并使用收到的数据来发起或支持各种交互。 客户端也可以使用套接字与服务器通信,例如在成功收到更新时发送 ACK 消息。 - SSE 是一种更简单的标准,是作为 HTML5 的扩展而开发的。 尽管 SSE 支持从服务器向客户端发送异步消息,但客户端无法向服务器发送消息。 对于客户端只需接收从服务器传入的更新的应用程序,SSE 的半双工通信模型最适合。 与 WebSocket 相比,SSE 的一个优势是它是基于 HTTP 而运行的,不需要其他组件。

几乎所有现代浏览器都支持 WebSocket 协议,包括移动浏览器。然而Microsoft IE 和 Edge不支持SSE 但这并不妨碍我们使用SSE,毕竟用IE的人还有几个呢?如果是内部使用,为什么不使用更简单的SSE呢?

这里讲述如何使用SSE建立服务端的推送。

二、服务端

这里我们使用聊天来模拟SSE的数据推送。我这里写了几个自定义的对象 - Chater对象存储聊天人的信息。 - WebSSEUser是一个存储用户名userName和Chater对象的map。

2.1 配置

在Springboot项目中使用SSE,是不需要额外引入依赖的,只需要把spring-boot-starter-web引入即可。也不需要额外的配置。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2.2 服务端text/event-stream长连接

要使用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接口: - produces指定了响应类型text/event-stream - userName从session中获取,并获取到聊天对象Chater。 - 这里调用时创建SseEmitter对象,设置超时时间3分钟,onTimeout超时后清除SseEmitter对象,因为SSE可以超时重连,超时会再次调用这个接口,就会重新生成SseEmitter对象。 - onCompletion完成后逻辑自定义,但是不要清除SseEmitter对象,否则会一直重连。

SSE调用/subscribe接口接口以后,会一直使用一个请求,类似websocket。

2.3 服务端发送消息

上面的代码只是保持了长连接,而且是单向的,只能是服务端给客户端发消息。

单向的意思就是,客户端不能通过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的方法。下面讲述下客户端如何操作。

3.1 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);

3.2 普通http请求发送消息

普通的ajax请求即可,无需额外处理,调用服务端的/send接口即可。

四、控制台截图

如图:

SSE(Server-Sent Events)实现聊天功能控制台截图
  1. 客户端连接服务端的/subscribe接口,这个连接会一直持续下去,图上已经持续了十几秒。
  2. 客户端连接服务端的/send接口,发送消息给服务端,服务端转发给其他客户端。

到此这篇关于Spring Boot中使用SSE(Server-Sent Events)实现聊天功能:替代websocket服务器推送的文章就介绍到这了,更多相关SSE(Server-Sent Events)替代websocket内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java实现读取txt文件中的内容

    java实现读取txt文件中的内容

    本文通过一个具体的例子向大家展示了如何使用java实现读取TXT文件里的内容的方法以及思路,有需要的小伙伴可以参考下
    2016-03-03
  • 详解JavaScript中的函数声明和函数表达式

    详解JavaScript中的函数声明和函数表达式

    这篇文章主要介绍了详解JavaScript中的函数声明和函数表达式,是JS入门学习中的基础知识,需要的朋友可以参考下
    2015-08-08
  • Java中memcached的cache机制

    Java中memcached的cache机制

    这篇文章主要介绍了Java中memcached的cache机制,在Java中使用Memcached的缓存机制需要使用Java的Memcached客户端库。Memcached是一个高性能的分布式内存缓存系统,可以用来缓存常用的数据,需要的朋友可以参考下
    2023-07-07
  • Java规则引擎Easy Rules的使用介绍

    Java规则引擎Easy Rules的使用介绍

    这篇文章主要介绍了Java规则引擎Easy Rules的使用介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Java注解使用及原理解析

    Java注解使用及原理解析

    这篇文章主要介绍了Java注解使用及原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • java 获取内存使用率的流程实例详解

    java 获取内存使用率的流程实例详解

    这篇文章主要为大家介绍了java 获取内存使用率的流程实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • java轻量级规则引擎easy-rules使用介绍

    java轻量级规则引擎easy-rules使用介绍

    这篇文章主要介绍了java轻量级规则引擎easy-rules使用介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Jmeter内置变量vars和props的使用详解

    Jmeter内置变量vars和props的使用详解

    JMeter是一个功能强大的负载测试工具,它提供了许多有用的内置变量来支持测试过程,其中最常用的变量是 vars 和 props,本文通过代码示例详细给大家介绍了Jmeter内置变量vars和props的使用,需要的朋友可以参考下
    2024-08-08
  • 一次java异步任务的实战记录

    一次java异步任务的实战记录

    最近做项目的时候遇到了一个小问题,从前台提交到服务端A,A调用服务端B处理超时,下面这篇文章主要给大家介绍了一次java异步任务的实战记录,需要的朋友可以参考下
    2022-05-05
  • ssm项目session使用及其作用域问题

    ssm项目session使用及其作用域问题

    这篇文章主要介绍了ssm项目session使用及其作用域问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03

最新评论