使用Java和SpringBoot实现服务器发送事件(Server-Sent Events)

 更新时间:2024年02月06日 09:07:40   作者:基督山伯爵_Neo  
使用Java开发web应用,大多数时候我们提供的接口返回数据都是一次性完整返回,有些时候,我们也需要提供流式接口持续写出数据,以下提供一种简单的方式,本文给大家介绍了如何在Java web中实现服务器发送事件,需要的朋友可以参考下

引言

使用Java开发web应用,大多数时候我们提供的接口返回数据都是一次性完整返回。有些时候,我们也需要提供流式接口持续写出数据,以下提供一种简单的方式。

SSE(Server-Sent Events)

SSE 是一种允许服务器单向发送事件到客户端的技术,它基于HTTP协议,服务器可以推送消息到客户端,但客户端不能向服务器发送消息。

实现

直接上代码

@RestController
public class TestController {

    private static final Logger logger = LoggerFactory.getLogger(TestController.class);

    @GetMapping("/test")
    public void test(HttpServletResponse response) {
        response.setContentType("text/event-stream");
        response.setCharacterEncoding("utf-8");

        try (final PrintWriter writer = response.getWriter()) {
            // 要推送的内容
            final String content = "你好,我的朋友,快过年了,提前祝你新年快乐!";
            int len = content.length();
            int endIndex = 0;
            // 每隔2个字符推送一次,模拟打字机效果
            while (endIndex < len) {
                endIndex = Math.min(endIndex + 2, len);
                final String subContent = content.substring(0, endIndex);
                // 将要推送的内容封装成JSON格式,模拟实际开发中的数据格式,非必须
                final JSONObject json = new JSONObject();
                json.put("data", subContent);
                json.put("code", HttpStatus.OK.value());
                // 最后一次推送时,type为finish,表示推送结束,其它情况为add
                final String type = endIndex == len
                        ? "finish"
                        : "add";
                json.put("type", type);
                // 组装成SSE格式的数据,发送给前端,这个格式(data: content\n\n)是固定的,content是自定义的推送内容
                writer.write("data: " + json.toJSONString() + "\n\n");
                writer.flush();
                // 稍微给点停顿,防止数据发送太快,浏览器接收不过来
                TimeUnit.MILLISECONDS.sleep(100);
            }
        } catch (Exception e) {
            Thread.currentThread().interrupt();
            logger.error("流式推送数据异常", e);
        }
    }
}

组装数据,格式固定为"data: " + content + "\n\n",这里的数据格式是服务器发送事件(Server-Sent Events,SSE)的标准格式。

SSE 中,数据必须以 "data: " 开头,然后是要发送的数据,最后是两个换行符"\n\n"。这是SSE的规定格式,客户端会根据这种格式来解析服务器发送的事件。

接口调试

用接口调试工具(我用的是Apifox)调试接口如下:

接口符合SSE规范,所以可以被正常识别为事件流推送。

SSE与其他实时通信技术的比较

SSE与WebSocket的比较

  • 通信方式:SSE是单向的,只能由服务器向客户端发送数据;而WebSocket是双向的,服务器和客户端都可以发送数据。
  • 协议:SSE基于HTTP协议,更易于设置和配置;WebSocket是一个独立的协议。
  • 数据格式:SSE发送的数据格式固定,必须是"text/event-stream";而WebSocket可以发送任何类型的数据。
  • 连接:SSE在断开连接后可以自动重新连接,而WebSocket需要手动处理重连。
  • 浏览器支持:WebSocket的浏览器支持更广泛,几乎所有现代浏览器都支持WebSocket;而SSE在某些旧版本的浏览器(如IE)中不被支持。

SSE与长轮询的比较

  • 效率:SSE更高效,因为它只需要一个HTTP连接,就可以持续地发送数据;而长轮询需要不断地建立和断开HTTP连接。
  • 实时性:SSE的实时性更强,因为服务器可以随时发送数据;而长轮询需要客户端不断地发送请求来获取新数据。
  • 复杂性:SSE的实现相对简单,只需要服务器按照规定的格式发送数据即可;而长轮询的实现较复杂,需要处理连接的建立和断开,以及错误和超时等问题。
  • 浏览器支持:与WebSocket相比,SSE和长轮询的浏览器支持都较差,但长轮询在更多的浏览器中被支持。
  • 适用场景:SSE适用于服务器需要主动推送数据的场景;而长轮询适用于客户端需要定期获取新数据,但服务器不需要主动推送数据的场景。

注意事项

  • 以上一个简单的事件流推送接口就实现好了,但是它的问题是客户端没法干预服务器的推流,如果需要中途停止接收内容,基于以上接口是没法做到的。所以实际项目开发过程中,可以使用Spring框架提供的SseEmitter
  • ​​​​​浏览器支持:并非所有浏览器都支持SSE,例如,旧版本的Internet Explorer就不支持SSE。在使用SSE时,需要确保目标用户的浏览器支持这项技术。
  • 连接限制:由于SSE需要保持长连接,因此可能会占用大量的服务器资源。在使用SSE时,需要考虑到这一点,并根据实际情况进行优化。

以上就是使用Java和SpringBoot实现服务器发送事件(Server-Sent Events)的详细内容,更多关于Java SpringBoot服务器发送事件的资料请关注脚本之家其它相关文章!

相关文章

  • SpringMVC整合,出现注解没有起作用的情况处理

    SpringMVC整合,出现注解没有起作用的情况处理

    这篇文章主要介绍了SpringMVC整合,出现注解没有起作用的情况及处理,具有很好的参考价值,希望对大家有所帮助。
    2023-05-05
  • spring学习之util:properties的使用

    spring学习之util:properties的使用

    这篇文章主要介绍了spring学习之util:properties的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Spring深入分析容器接口作用

    Spring深入分析容器接口作用

    Spring内部提供了很多表示Spring容器的接口和对象,我们今天来看看几个比较常见的容器接口和具体的实现类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • 新建springboot项目时,entityManagerFactory报错的解决

    新建springboot项目时,entityManagerFactory报错的解决

    这篇文章主要介绍了新建springboot项目时,entityManagerFactory报错的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • jdk17 SpringBoot JPA集成多数据库的示例详解

    jdk17 SpringBoot JPA集成多数据库的示例详解

    这篇文章主要介绍了jdk17 SpringBoot JPA集成多数据库的示例代码,包括配置类、请求拦截器、线程上下文等相关知识,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • Java集合排序规则接口Comparator用法解析

    Java集合排序规则接口Comparator用法解析

    这篇文章主要介绍了Java集合排序规则接口Comparator用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • java线程并发countdownlatch类使用示例

    java线程并发countdownlatch类使用示例

    javar的CountDownLatch是个计数器,它有一个初始数,等待这个计数器的线程必须等到计数器倒数到零时才可继续。
    2014-01-01
  • Ajax实现省市区三级联动

    Ajax实现省市区三级联动

    这篇文章主要为大家详细介绍了jQuery ajax实现省市县三级联动的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能帮助到你
    2021-07-07
  • JAVA获取Image的三种方式

    JAVA获取Image的三种方式

    这篇文章主要介绍了JAVA获取Image的三种方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Java如何在命令行中获取指定数据

    Java如何在命令行中获取指定数据

    这篇文章主要介绍了Java如何在命令行中获取指定数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07

最新评论