SSE介绍

目录

SSE概念

SSE的特点

应用场景

优点

缺点

轮询(Polling)概念

轮询特点

应用场景

优点

缺点

Websocket概念

特点

应用场景

优点

缺点

SSE、轮询、websocket对比

SSE实现

pom依赖

SSE控制器

postman模拟客户端发起请求

总结


SSE概念

SSE(Server-Sent Events)是一种服务器向客户端推送实时数据的技术。

SSE的特点

  • 单向通信:服务器向客户端推送数据,客户端不能通过 SSE 向服务器发送数据
  • 基于 HTTP:使用标准的 HTTP 协议,长连接方式
  • 自动重连:客户端在连接断开时会自动重连
  • 轻量级:实现简单,适合服务器向客户端推送实时数据的场景

应用场景

  • 实时通知:如新闻更新、股票价格变动、天气预报等。

  • 日志推送:服务器向客户端实时推送日志信息。

  • 进度更新:如文件上传/下载进度、任务处理进度等。

优点

  • 实现简单,兼容性好(基于 HTTP)。

  • 支持自动重连,适合长时间运行的场景。

缺点

  • 单向通信,客户端无法通过 SSE 向服务器发送数据。

  • 不支持二进制数据,只支持文本数据。

轮询(Polling)概念

轮询特点

  • 客户端主动请求:客户端定期向服务器发送请求,检查是否有新的数据
  • 高延迟:数据更新的实时性取决于客户端的轮询间隔
  • 资源消耗:频繁的请求会增加客户端和服务器的资源消耗

应用场景

简单,对实时性要求不高的场景,如简单的状态检查、数据更新等

优点

  • 实现简单,兼容性好
  • 适合对实时性要求不高的应用场景

缺点

  • 高延迟,实时性差
  • 频繁请求,浪费资源

Websocket概念

特点

双向通信:客户端和服务器可以实时双向通信

基于TCP:使用独立的websocket协议,性能高

低延迟:适合实时性要求很高的场景

应用场景

实时聊天:如在线客服、聊天室等

实时协作:如在线文档编辑、多人游戏等

高频数据交互:如股票交易、数据监控等

优点

  • 低延迟,实时性高
  • 支持双向通信

缺点

  • 实现复杂,需要额外的websocket协议支持
  • 对服务器资源消耗较大

SSE、轮询、websocket对比

|-----------|------------|-----------|-----|-------|------------------|
| 技术 | 通信方式 | 协议 | 实时性 | 实现复杂度 | 适用场景 |
| SSE | 单向,服务器→客户端 | HTTP | 高 | 简单 | 实时通知、进度更新、日志推送等 |
| 轮询 | 单向,客户端→服务器 | HTTP | 低 | 简单 | 简单数据更新、状态检查 |
| websocket | 双向通信 | websocket | 极高 | 复杂 | 实时聊天、在线协作、高频数据交互 |

SSE实现

在springboot项目中,实现一个简单的SSE程序,步骤如下

pom依赖

复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

SSE控制器

java 复制代码
package com.tml.mouseDemo.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.ttl.threadpool.TtlExecutors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class SSEController {

    // 存储所有连接的客户端(线程安全)
    private final CopyOnWriteArrayList<SseEmitter> emitters = new CopyOnWriteArrayList<>();

    // 定时任务线程池
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    //使用ttl装饰线程池,是为了方便使用threadLocal
    ScheduledExecutorService ttlScheduledExecutorService = TtlExecutors.getTtlScheduledExecutorService(scheduler);

    /**
     * 客户端连接 SSE 的入口
     * sse的content-type是text/event-stream
     */
    @GetMapping(path = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter handleSSE(@RequestParam String userId) {


        SseEmitter emitter = new SseEmitter(60_000L); // 超时时间 60 秒

        // 将新的 emitter 加入集合
        emitters.add(emitter);
        log.info("SSE emitter started");

        // 注册完成和超时的回调(清理资源)
        emitter.onCompletion(() -> {
            log.info("SSE emitter stopped");
            emitters.remove(emitter);
        });
        emitter.onTimeout(() -> {
            log.info("SSE emitter timeout");
            emitters.remove(emitter);
        });

        // 启动定时任务,向客户端推送数据
        ttlScheduledExecutorService.scheduleAtFixedRate(() -> {
            try {
                String message = "Hello " + userId + "! Time: " + DateUtil.now();
                log.info("SSE emitter sending message: {}", message);
                emitter.send(message);
            } catch (IOException e) {
                emitter.completeWithError(e);
            }
        }, 0, 5, TimeUnit.SECONDS); // 每5秒发送一次

        return emitter;
    }
}

启动服务端后,再启动客户端

postman模拟客户端发起请求

总结

在AI时代,很多大模型的开放平台的api均支持流式返回和非流式返回,这里的流式返回,就是使用的SSE,比如kimi的开放平台

在实际应用中,可能还有其他场景适用服务器单向客户端推送数据,这个时候SSE就派上用场了,欢迎评论区留言,说出你们实际业务中,有哪些场景使用了SSE!

相关推荐
喻米粒062242 分钟前
RabbitMQ消息相关
java·jvm·spring boot·spring·spring cloud·sentinel·java-rabbitmq
Aphelios3803 小时前
Java全栈面试宝典:线程机制与Spring IOC容器深度解析
java·开发语言·jvm·学习·rbac
qq_529835353 小时前
装饰器模式:如何用Java打扮一个对象?
java·开发语言·装饰器模式
日暮南城故里3 小时前
Java学习------源码解析之StringBuilder
java·开发语言·学习·源码
一个public的class6 小时前
什么是 Java 泛型
java·开发语言·后端
士别三日&&当刮目相看6 小时前
JAVA学习*Object类
java·开发语言·学习
快来卷java6 小时前
MySQL篇(一):慢查询定位及索引、B树相关知识详解
java·数据结构·b树·mysql·adb
青花瓷6 小时前
智谱大模型(ChatGLM3)PyCharm的调试指南
人工智能·python·大模型·智谱大模型
凸头7 小时前
I/O多路复用 + Reactor和Proactor + 一致性哈希
java·哈希算法
慵懒学者7 小时前
15 网络编程:三要素(IP地址、端口、协议)、UDP通信实现和TCP通信实现 (黑马Java视频笔记)
java·网络·笔记·tcp/ip·udp