SSE—实时数据推送新选择

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

一, 主要特点

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

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

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

二,和WebSocket对比

WebSocket搭建看这个:10行Java代码实现站内信,一看就会-CSDN博客

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

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

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

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

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

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

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

三,SSE实现

1,SpringBoot项目

<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>

2,引入测试用的html文件的thymeleaf配置

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

3,接口实现

import cn.hutool.core.lang.UUID;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@RestController
@RequestMapping("/sse")
@Slf4j
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 -> {
            log.info("userId: {}, errot: {}", id, ex.getMessage());
            sse.remove(id) ;
        }) ;
        // 异步请求完成后的回调
        emitter.onCompletion(() -> {
            sse.remove(id) ;
            log.info("请求完成: {}", id);
        }) ;
        // 异步请求超时回调
        emitter.onTimeout(() -> {
            sse.remove(id) ;
            log.info("请求超时: {}", id);
        }) ;
        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( "随机消息 - " + UUID.fastUUID()) ;
            } catch (Exception e) {
                log.error("出现异常: ", e);
            }
        }
        return "success" ;
    }
}

4,html测试文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SSE</title>
</head>
<body>
<button type="button" οnclick="closeSse()">关闭</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>

5,测试

http://localhost:8201/sse/sender/321312321  模拟服务器端发送消息的接口

http://localhost:8201/sse/events/321312321  监听服务端消息,并展示出来

http://localhost:8201/sse.html  展示关闭按钮的页面

四,总结

服务器端和客户端(浏览器)的通信一直是比较常见的需求,SSE是比较适合快速开发的单向通信技术,如果遇到只需要服务器推送消息到客户端的,可以选择这个来实现。

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东皋长歌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值