实时数据推送并非只有WebSocket一种选择

环境:SpringBoot2.7.16


概述

在Web应用中,有几种实时数据推送的选择方案,包括SSE(Server-Sent Events)、WebSocket、长轮询等。

SSE是一种基于HTTP协议的服务器向客户端推送数据的技术。它的优点是实现简单、轻量级,对现有服务器软件兼容性好。但是,由于SSE是单向通信模型,只能由服务器向客户端推送数据,对于需要客户端向服务器发送数据的场景,SSE就无法满足需求。

WebSocket是一种双向通信模型,允许客户端和服务器之间互相发送消息。它的优点是实时性强、延迟低,但是需要服务器端支持对应的协议栈,实现起来相对复杂一些。

长轮询是对短轮询的一种改进版本,通过在尽可能减少对服务器资源浪费的同时,保证消息的相对实时性。长轮询在客户端发起请求时,服务器会保持连接打开,等待一定时间后再返回响应。这样可以减少客户端频繁的请求,节省带宽和服务器资源。但是,如果服务器没有新的消息产生,客户端会一直等待响应,实时性就会受到一定影响。

根据实际应用场景和需求,可以选择适合的实时数据推送方案。如果只需要服务器向客户端推送数据,且对实时性要求不是特别高,可以选择SSE。如果需要客户端向服务器发送数据,或者对实时性要求较高,可以选择WebSocket或长轮询。当然,也可以根据实际情况将这几种方案结合起来使用,以满足不同的需求。

SSE与WebSocket对比

SSE(Server-Sent Events)和WebSocket都是用于实现实时通信的技术,存在关键差异。

通信模型:SSE是单向通信模型,只能由服务器向客户端推送数据。而WebSocket是双向通信模型,客户端和服务器可以互相发送消息。

连接性:SSE使用长轮询或HTTP流技术,需要频繁地发起HTTP请求来获取数据。而 WebSocket只需在握手阶段建立一次连接,然后保持连接打开,减少了频繁建立连接的开销。

实时性:WebSocket提供了更低的延迟和更高的实时性,因为它支持双向通信,可以立即将数据推送给客户端。SSE虽然也可以实现实时性,但由于其单向通信模型,需要服务器定期发送数据。

协议特性:SSE是部署在HTTP协议之上的,现有的服务器软件都支持。而WebSocket是一个新的协议,需要服务器端支持对应的协议栈。

复杂性:SSE相对WebSocket来说更轻量级,实现更简单。WebSocket协议较复杂,实现相对困难一些。

总体来说,SSE和WebSocket都有各自的优点和适用场景。SSE轻量级且对现有服务器软件兼容性好,而WebSocket则提供了更强的双向通信能力和更高的实时性。

SSE简介

SSE(Server-Sent Events)是一种用于实现服务器向客户端实时推送数据的Web技术。与传统的轮询和长轮询相比,SSE提供了更高效和实时的数据推送机制。

SSE基于HTTP协议,允许服务器将数据以事件流(Event Stream)的形式发送给客户端。客户端通过建立持久的HTTP连接,并监听事件流,可以实时接收服务器推送的数据。

SSE的主要特点包括:

简单易用:SSE使用基于文本的数据格式,如纯文本、JSON等,使得数据的发送和解析都相对简单。

单向通信:SSE支持服务器向客户端的单向通信,服务器可以主动推送数据给客户端。

实时性:SSE建立长时间的连接,使得服务器可以实时地将数据推送给客户端,而无需客户端频繁地发起请求。

服务端开发

依赖管理

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

配置文件

spring:
  mvc:
    static-path-pattern: /**
  web:
    resources:
      #静态文件目录index.html
      static-locations: classpath:/templates/

接口开发

@RestController
@RequestMapping("/sse")
public class SseController {
  
  // 该集合用来管理所有客户端的连接
  private final Map<String, SseEmitter> sse = new ConcurrentHashMap<>() ;

  // 创建连接接口,同时指定了消息类型为text/event-stream
  @GetMapping(path="/events/{id}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  public SseEmitter createConnect(@PathVariable("id") String id) throws IOException {
    SseEmitter emitter = new SseEmitter(0L);
    // 每一个客户端保存到Map中
    sse.put(id, emitter) ;
    // 当发生错误的回调
    emitter.onError(ex -> {
      System.err.printf("userId: %s, error: %s%n", id, ex.getMessage()) ;
      sse.remove(id) ;
    }) ;
   // 异步请求完成后的回调
    emitter.onCompletion(() -> {
      sse.remove(id) ;
      System.out.printf("%s, 请求完成...") ;
    }) ;
    // 异步请求超时回调
    emitter.onTimeout(() -> {
      System.err.println("超时...") ;
    }) ;
    return emitter;
  }
  
  // 该接口用来进行消息的发送
  // 由客户端发起请求,然后根据id获取相应的SseEmitter进行消息的发送
  @GetMapping("/sender/{id}")
  public String sender(@PathVariable("id") String id) throws Exception {
    SseEmitter emitter = this.sse.get(id) ;
    if (emitter != null) {
      try {
        emitter.send( "随机消息 - " + new Random().nextInt(10000000)) ;
      } catch (Exception e) {
        System.err.println("%s%n", e.getMessage()) ;
      }
    }
    return "success" ;
  }
}

前端开发

前端比较简单就是一个index.html页面​​​​​​​

<html>
  <head>
  <title>SSE</title>
</head>
<body>
  <button type="button" onclick="closeSse()">Close</button>
  <hr style="margin: 2px; padding: 0px 0px;"/>
  <ul id="list"></ul>
</body>
<script>
  const evtSource = new EventSource(`/sse/events/${Date.now()}`) ;
  evtSource.onmessage = (event) => {
    const newElement = document.createElement("li") ;
    const eventList = document.getElementById("list") ;
    newElement.innerHTML = "接收到消息: " + event.data ;
    eventList.appendChild(newElement) ;
  };
  evtSource.onopen = (event) => {
    console.log('建立连接...')
  };
  evtSource.onerror = (event) => {
    console.error("发生错误:", event) ;
  };
  function closeSse() {
    evtSource.close() ;
  }
</script>
</html>

以上就是前后端的开发,代码非常的简单;也就简单的实现了由服务端实时数据推送。

EventSource对象的readyState有3个状态值:

0 — connecting

1 — open

2 — closed

测试

图片

调用消息发送接口

图片

图片

自定义事件类型

修改消息发送接口​​​​​​​

@GetMapping("/sender/{id}")
  public String sender(@PathVariable("id") String id) throws Exception {
    SseEmitter emitter = this.sse.get(id) ;
    if (emitter != null) {
      SseEventBuilder builder = SseEmitter.event() ;
      // 指定事件类型
      builder.name("chat") ;
      String msg = "随机消息 - " + new Random().nextInt(10000000);
      builder.data(msg) ;
      try {
        emitter.send(builder) ;
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    return "success" ;
  }

前端监听具体事件类型消息​​​​​​​

evtSource.addEventListener("chat", (event) => {
  const newElement = document.createElement("li");
  const eventList = document.getElementById("list");

  newElement.innerHTML = "chat message: " + event.data;
  eventList.appendChild(newElement);
});

注意:默认是“message”事件,因为它可以捕获没有 event 字段的事件, * 以及具有特定类型 `event:message` 的事件。* 它不会触发任何其他类型的事件。

完毕!!!

关注+转发

关注公众号,全都是实战案例

图片

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WebSocket一种基于TCP的网络协议,它实现了浏览器与服务器之间的全双工通信,允许服务器主动向客户端推送信息,从而实现实时数据推送的功能。\[3\] 在使用WebSocket实现实时推送数据的过程中,需要在前后端分别进行相应的配置和代码编写。 在后端,需要创建一个WebSocket服务器,并在服务器端代码中编写发送消息的逻辑。可以使用Java的Spring框架提供的WebSocket支持,通过@EnableScheduling注解开启定时任务,并在定时任务中调用WebSocket服务器的sendAllMessage方法发送消息。\[2\] 在前端,需要使用JavaScript代码来建立WebSocket连接,并监听服务器端发送的消息。可以使用WebSocket的API来创建WebSocket对象,并通过onmessage事件监听服务器端发送的消息。一旦接收到消息,就可以进行相应的处理,例如更新页面上的数据。\[1\] 通过以上的配置和代码编写,就可以实现WebSocket实时推送数据的功能。当服务器端有新的数据需要推送时,会主动发送消息给客户端,客户端接收到消息后可以进行相应的处理,实现实时更新数据的效果。 #### 引用[.reference_title] - *1* *3* [webSocket实现数据实时推送(附:前后端代码)](https://blog.csdn.net/weixin_42555014/article/details/124140649)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [SpringBoot集成WebSocket实现消息实时推送(提供Gitee源码)](https://blog.csdn.net/HJW_233/article/details/131326572)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值