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!

相关推荐
geovindu31 分钟前
java: framework from BLL、DAL、IDAL、MODEL、Factory using postgresql 17.0
java·开发语言·postgresql
缘来是黎41 分钟前
Python 进阶:生成器与上下文管理器
java·前端·python
m0_7482402543 分钟前
【Spring Boot】统一数据返回
java·spring boot·后端
陈老师还在写代码1 小时前
介绍下SpringBoot常用的依赖项
java·spring boot·后端
程序猿零零漆1 小时前
《从入门到精通:蓝桥杯编程大赛知识点全攻略》(十一)-回文日期、移动距离、日期问题
java·算法·蓝桥杯
众乐乐_20081 小时前
JVM栈帧中|局部变量表、操作数栈、动态链接各自的任务是什么?
java·开发语言·jvm
m0_748239332 小时前
深入解析Spring Boot中的@ConfigurationProperties注解
java·spring boot·后端
茂桑4 小时前
Redis的数据过期策略和数据淘汰策略
java·数据库·redis
涟漪海洋4 小时前
[2025年最新]2024.3版本idea无法安装插件问题解决
java·ide·intellij-idea
土豆炒马铃薯。4 小时前
【系统设计】Spring、SpringMVC 与 Spring Boot 技术选型指南:人群、场景与实战建议
java·spring boot·后端·spring