流式输出的Java实战-SSE在Spring里怎么接

Java实现SSE流式输出:从Servlet到虚拟线程的三种方案 SSE(Server-Sent Events)是一种基于HTTP的单向服务端推送技术,通过保持长连接持续发送文本数据,天然支持断线重连,适合AI对话等流式输出场景。在Java中,SSE可通过原生Servlet、Spring SseEmitter或WebFlux响应式方案实现,而JDK21虚拟线程的引入进一步提升了高并发下的性能表现。虚拟线程以极低的内存开销支持百万级连接,解决了传统线程池在SSE长连接场景下的资源瓶颈。该技术广泛应用于大模型流式响应、实时日志推送、消息通知等场景。本文深入拆解Java实现SS 阅读详情

流式输出的 Java 实战:SSE 在 Spring 里怎么接

打字机效果前端等着要,后端返回一坨 JSON 就没戏。理论篇讲过,流式就是一次不收尾的 HTTP 响应,一行一块的 data 推给浏览器。这篇把落地的活补上:报文长什么样、Spring 里两种接法、反向代理和超时的坑,最后给你一个单文件的实验台。

先看报文

服务端把 Content-Type 设成 text/event-stream,然后一块一块写,data: 开头是数据行,空行是事件结束。

HTTP/1.1 200 OK
Content-Type: text/event-stream

data: {"delta": "北京"}

data: {"delta": "25 度"}

data: [DONE]

Java 侧的活就是维持这个响应不关,往里写行。Spring 把这件事封装成了两种姿势。

Spring 的两种接法

第一种,SseEmitter,MVC 的老朋友。方法返回一个 SseEmitter,你拿到它想什么时候发就什么时候发,send 发事件,complete 收尾。适合任何 Spring MVC 工程。

@GetMapping("/chat/stream")
public SseEmitter chatStream(@RequestParam String question) {
    SseEmitter emitter = new SseEmitter(60_000L);   // 60 秒超时
    CompletableFuture.runAsync(() -> {
        try {
            for (String delta : model.stream(question)) {   // 模型的流
                emitter.send(SseEmitter.event().data(delta));
            }
            emitter.complete();
        } catch (Exception e) {
            emitter.completeWithError(e);
        }
    });
    return emitter;
}

第二种,Spring AI 的 stream()。框架直接给你 Flux 形状的增量流,WebFlux 或者带 reactor 的工程里最顺手,一行 call 换 stream 的事。

Flux<String> tokens = chatClient.prompt()
        .user(question)
        .stream()
        .content();

(Spring AI 的 stream API 形状按 1.x 之后的口径,方法名以你所用版本文档为准。)

三个坑

第一个,反向代理缓冲。Nginx 默认把上游响应攒够再发,流式就变成「等半天一坨」,要在反向代理配置里关掉缓冲(proxy_buffering off)。这一条在反向代理篇讲过,这里是它的实战现场。
第二个,超时两头设。SseEmitter 有自己的超时,网关和反向代理也有空闲超时;流式响应没有数据流动时容易被中间设备掐断,定时发一个心跳注释行(: ping),连接就能活着。
第三个,错误别裸抛。流推到一半炸了,响应头早就发出去了,HTTP 状态码改不了,只能在流里发一个 error 事件再关,前端要能接住这个形状。

心跳 : ping

error 事件

模型增量

后端逐块 send

nginx 别缓冲

前端逐块渲染

亲手开一个实验台

下面用一段 Java 起一个 SSE 服务,JDK 自带的 HttpServer 写 text/event-stream,客户端连上逐块打印。直接运行 java SseLab.java(JDK 11+),看字符一块一块到。

// 直接运行:java SseLab.java
// SSE 实验台:服务端逐块推送,客户端逐块到达。

import com.sun.net.httpserver.HttpServer;
import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

public class SseLab {

    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new java.net.InetSocketAddress("127.0.0.1", 0), 0);
        server.createContext("/stream", exchange -> {
            exchange.getResponseHeaders().add("Content-Type", "text/event-stream");
            exchange.sendResponseHeaders(200, 0);   // 0 表示长度未知,流式
            var out = exchange.getResponseBody();
            String[] tokens = {"北京", "今天", "25 度", ",晴"};
            for (String t : tokens) {
                out.write(("data: " + t + "\n\n").getBytes(StandardCharsets.UTF_8));
                out.flush();
                Thread.sleep(200);                 // 模拟模型一块块生成
            }
            out.write("data: [DONE]\n\n".getBytes(StandardCharsets.UTF_8));
            out.flush();
            out.close();
        });
        server.start();
        int port = server.getAddress().getPort();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("http://127.0.0.1:" + port + "/stream"))
                .build();
        HttpResponse<InputStream> resp = HttpClient.newHttpClient()
                .send(request, HttpResponse.BodyHandlers.ofInputStream());

        System.out.println("客户端开始收流:");
        try (var reader = new java.io.BufferedReader(
                new java.io.InputStreamReader(resp.body(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("data: ")) {
                    System.out.println("  收到一块:" + line.substring(6));
                    if (line.contains("[DONE]")) {
                        break;
                    }
                }
            }
        }
        server.stop(0);
        System.out.println("流结束。每块之间隔着 200ms,这就是打字机的节奏。");
    }
}

记住一句话:流式是不收尾的响应,后端的活是别关连接、别攒缓冲、别裸抛错误。

适用边界

这一篇管 SSE 的 Java 落地。WebSocket 的双向场景、HTTP/2 下的流式,以及前端渲染的增量合并,是另外的题。Spring AI 的 stream 各版本方法名有微调,本文按公开文档口径整理。跑完实验台再接真模型,中间件的每一层(网关、反向代理、CDN)都要过一遍「会不会缓冲」的检查——打字机效果是全链路的体面。

电力抄表协议DL/T645和698.45到底有啥区别?一张图帮你选对协议 本文深入对比了电力抄表协议DL/T645和DL/T698.45的技术差异,从协议架构、报文结构、功能覆盖到实施成本进行全面分析。通过实际案例和数据,揭示698.45协议在通信效率、业务扩展性和长期成本上的优势,并提供清晰的选型决策流程图,帮助工程师根据具体需求选择最适合的电力抄表协议。 阅读详情

相关推荐

在后端设计中,GDSLL,LEF,DEF,SDF,SPEF,SDC各代表什么意思?前端和中端流程中,SVF,SAIF又代表什么意思?

在后端设计中,GDSLL,LEF,DEF,SDF,SPEF,SDC区别?前端和中端流程中,SVF,SAIF代表什么意思?

weixin_43274923的博客 1万+

Java Spring Boot实现AI流式输出:SSE协议原理与实战指南

在构建现代AI应用时,提升用户体验的关键在于实现实时、流畅的交互。流式输出技术允许服务器将生成内容以数据流的形式持续推送给客户端,从而消除用户等待的焦虑感,模拟真人对话的即时反馈。其核心原理基于HTTP长连接与事件流协议,通过服务器主动推送数据块,实现内容的逐字或逐词呈现。在Java生态中,Spring Boot框架结合Server-Sent Events(SSE)协议,为AI流式输出提供了轻量且高效的解决方案。SSE作为一种服务器向客户端的单向通信机制,特别适用于新闻更新、股票行情推送及AI内容生成等场景

weixin_30219613的博客 244

深入RK3588嵌入式Linux开发:uboot源码定制化移植实战

本文详细介绍了RK3588嵌入式Linux开发中,如何绕过庞大的官方SDK,从官方仓库获取纯净U-Boot源码并进行定制化移植的完整实战流程。内容包括编译环境搭建、交叉工具链配置、源码结构解析、设备树(Device Tree)修改、环境变量定制、编译脚本编写以及常见问题调试技巧,旨在帮助开发者深入理解系统引导过程,掌握为定制硬件适配U-Boot的核心技能。

weixin_29169505的博客 423

SpringBoot手动实现流式输出方案整理以及SSE规范输出详解

本文探讨了Java实现流式输出的多种方案,重点介绍了基于SSE规范的实现方式。通过对比Servlet原生API、ResponseBodyEmitter、WebFlux等技术,最终选择SSE方案以适应已采用SSE规范的前后端适配场景。文章详细解析了SSE协议格式、客户端API及适用场景,并提供了WebClient的配置方法、Service层实现和Controller示例代码。针对文件上传+SSE流响应的场景,特别说明了consumes和produces参数的配置要点。方案选择上推荐使用WebClient而非O

Alex的博客 4452

从零开始:MTK ISP调试中的ImagiqSimulator实战指南

本文详细介绍了MTK ISP调试中ImagiqSimulator的实战应用,从环境准备、参数加载到核心模块调整,提供全面的调试流程指南。重点讲解了DM模块参数优化技巧和常见问题解决方案,帮助工程师高效完成ISP调试工作,提升图像处理质量。

weixin_29168813的博客 489

QuickFix Java 讲解(一)概述、下载方法,和协议内容

本系列力求手把手教你怎样利用QuickFix Java 搭建自己的 FIX 协议收法平台,以及其中的注意事项。 所有源码的地址(免费): https://github.com/zongzhec/QuickFixPractise 1. 什么是FIX,QuickFix,Quick Java? 1.1. 什么是FIX 官网以及其他翻译自官网的帖子都太官方了,这里我们设想一个情景: 你是一个交易员,现在客户打电话来让你下个单买点股票。你啪啪啪的在你的机器上熟练地输入了下单指令。系统显示:成...

4574

Spring Boot SSE 流式输出,智能体的实时响应

在现代Web应用中,实时数据推送已经成为提升用户体验的关键技术。特别是在AI对话、实时监控、长任务执行等场景中,传统的请求-响应模式往往无法满足实时性需求。本文将详细介绍如何使用Spring Boot的SSE(Server-Sent Events)技术实现流式输出,并以AI智能体为例展示具体实现。SSE(Server-Sent Events)是一种允许服务器向客户端实时推送数据的技术。与WebSocket不同,SSE是单向通信(服务器→客户端),实现简单且浏览器兼容性好。简单的HTTP协议,无需额外协议。

2203_75376529的博客 2166

OpenClaw进阶实战(二十五):抖音企业号——私信回复与视频评论分析

摘要:本文介绍抖音企业号自动化运营方案,突破抖音强风控体系的技术挑战。针对内容生产、私信互动和账号矩阵三大场景,提出混合架构解决方案: 私信自动化:结合关键词触发与随机延迟(45秒±15),实现拟人化回复,支持价格咨询/商务合作等高优先级消息识别 混合技术栈:官方API(合规)+真机RPA(覆盖长尾需求)+AI辅助生成(脚本→剪辑→发布闭环) 安全策略:通过设备指纹模拟、行为间隔随机化和内容差异化处理规避风控,提供每日200条的安全操作阈值。配套OpenClaw技能实现一键部署,包含cookie配置、回复规

PeterPan的博客 144

Spring Boot 中基于 WebClient 的 SSE 流式接口实战

SSE(Server-Sent Events)是一种服务器主动推送的 HTTP 通信方式:基于 HTTP单向(服务端 → 客户端)长连接文本流(data: 你好data: 我是data: AI客户端可以一边接收,一边渲染。→ 行不通Feign 和 WebClient 的边界同步接口和流式接口在架构层面的本质差异AI 场景对交互模型的倒逼如果你现在也在做:AI 问答长文本生成实时推送那么,SSE 几乎是绕不开的一步。

“种一棵树最好的时间是十年前,其次就是现在。” 1235

YOLO-World:从入门到实战的多模态目标检测全指南

想象一下,你给模型一张“公园”的图片,再输入文字“红色的郁金香”,它能直接在图中框出所有红色郁金香的位置——这就是多模态目标检测:结合图像视觉信息和文本语义信息,同时完成“是什么”(分类)和“在哪里”(定位)的任务。传统目标检测(如YOLOv5、YOLOv8)只能识别预定义的类别(比如训练时学过“猫”“狗”),但多模态目标检测摆脱了“类别预定义”的限制,只要文本能描述,它就能检测,这就是“开放词汇检测(Open-Vocabulary Detection)”的魅力。

know_F0727的博客 205

机器学习实战7-基于机器学习算法预测相亲成功率

大家好,我是微学AI,今天给大家介绍一下机器学习实战7-基于机器学习算法预测相亲成功率,随着社会的发展,大家都忙于事业,对自己的终身大事就耽搁了,相亲是一种传统的寻找伴侣的方式,随着时代的发展,相亲的方式也在不断地改变。在这个过程中,了解相亲双方的信息以及预测相亲是否成功变得越来越重要。本文将介绍如何使用随机森林算法对相亲成功进行预测,通过分析男女双方的房子、车子、长相、家庭条件、父母情况、生活习惯、学历、性格、兴趣等因素,来预测相亲是否成功。

微学AI的博客 3034

AI流式输出的实现技术

SpringAI通过两种技术实现流式输出:一是基于Servlet的SpringMVC使用SseEmitter实现SSE协议,二是基于响应式编程的SpringWebFlux采用Reactor模型。其中SpringAI的流式输出底层采用与WebFlux相同的Reactor技术,通过异步非阻塞方式分批次传输AI生成内容,尤其适合大模型响应场景。SpringAIAlibaba作为国内最佳实践,继承了Spring生态优势,整合了阿里云AI能力,提供模型调用、Prompt模板等功能。这两种流式输出技术都能有效提升用户体

何哥的博客 2490

【项目实战】分布式日志系统 之 Exactly-once 语义:确保数据处理的精确性

在分布式系统的数据传输与处理中,是一种核心可靠性保障,其目标是确保数据“仅被处理一次”——既不重复(避免多次处理),也不遗漏(避免未处理)。与,二者共同保障数据处理的精确性。Exactly-once 语义是分布式系统中数据可靠性的高级目标,其核心通过“幂等设计”(解决重复问题)和“分布式事务”(解决原子性问题)实现。在实际应用中,常结合 At-Least-Once 语义与幂等性,或通过事务 API 与唯一 ID 去重的组合,平衡可靠性与系统性能。

奶爸的编程之路,也就一周冷个三天 167

SSE流式输出

用过 ChatGPT 的同学一定对那个“一个字一个字往外蹦”的效果印象深刻。很多人以为这是前端做的动画,其实它来自模型 API 本身的能力。如果你还在用同步调用让用户干等 10 秒才看到完整回复,那这篇文章就是为你准备的。本文将带你完整实现一个生产可用的流式对话系统:从 Spring AI 的基础,到 SSE 推送到前端,再到多轮记忆、异常处理和性能选型。全程有代码、有测试命令、有前端示例,跟着做就能直接搬进你的项目。

· 483

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

【简历进阶篇】SSE流式输出&&Spring WebFlux

本文介绍了SSE(Server-Sent Events)技术在Java项目中的实现与应用。SSE是一种基于HTTP的服务器向客户端单向推送数据的技术,适用于ChatGPT等大语言模型的流式输出场景。文章详细阐述了SSE与传统HTTP请求的区别,以及与WebSocket的对比,并提供了符合企业开发规范的SpringBoot实现方案,包括Controller层、Service层接口定义和实现类的代码示例。此外,文章还探讨了WebFlux框架在SSE实现中的优势,如高并发处理能力、非阻塞I/O操作和响应式编程模型

任岁月风干理想再也找不回真的我 2157

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Java WebFlux 实战:构建高效SSE流式数据转发服务

本文详细介绍了如何使用Spring WebFlux和WebClient构建高效的SSE流式数据转发服务。通过实战代码演示了如何将上游的流式数据源(如gRPC、WebSocket或SSE接口)无缝转换为前端可消费的SSE格式,并重点讲解了非阻塞转发、错误处理、性能调优及生产环境避坑指南,帮助开发者应对实时数据看板等场景下的高并发流式数据处理需求。

salt9的博客 1067

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Spring Boot集成SSE实现AI对话的流式响应

你只需要在App里点击一次“允许通知”(这就是建立连接),之后只要有新的大新闻发生,App服务器就会主动把消息推送到你的手机上,你不用一遍遍地去刷新App。你的浏览器(客户端)和我们的服务器(服务端)建立一个连接后,服务器就能随时把新数据(AI生成的新词语)主动“推送”给浏览器,而浏览器只管接收就行。注意这个接口的返回类型是 void,因为真正的响应是通过SSE推送的,而不是通过这个HTTP请求返回的。这是本次迭代的核心部分。通过本文的学习,我们成功地将一个普通的AI聊天应用升级为支持流式响应的版本。

xiangzhihong8的专栏 1639

Spring AI 实战:ChatMemory、SSE 流式输出与 Function Calling

能力解决的问题核心 APIChatMemory多轮对话记忆SSE 流式输出长回答的用户体验返回AI 调用外部系统@Tool@ToolParam.tools()ChatMemory 从内存开始,再升级 Redis。开发调试用内存版就够了,上生产再换 Redis 实现,代码改动极小。流式输出是标配。只要涉及面向用户的对话界面,一定用流式,体验差距是质变级别的。Function Calling 的 description 要花心思写。

qq_43552242的博客 764

流式输出技术SSE:前后端实践

当使用ChatGPT时,模型的回复不是一次性生成整个回答的,而是逐字逐句地生成。这是因为语言模型需要在每个时间步骤预测下一个最合适的单词或字符。如果等待整个回复生成后再输出到网页,会导致用户长时间等待,极大降低用户体验。相反,逐字蹦出回复可以实现更快的交互响应。ChatGPT可以在输入消息后迅速开始生成回答的开头,并根据上下文逐渐细化回答。这种渐进式的呈现方式可以提供更流畅的对话体验,同时让用户知道模型正在工作,避免感觉像卡住了或没有响应。

小匠的Blog 1657

Spring AI流式输出技术解析与SSE实现

流式输出技术是现代AI应用中的关键能力,它通过逐步推送计算结果显著提升用户体验。其核心原理基于Server-Sent Events(SSE)协议,这是一种轻量级的HTTP长连接技术,特别适合大语言模型响应、实时数据分析等单向数据推送场景。在Java生态中,Spring AI框架通过Reactor响应式编程模型实现高效的流式处理,结合EventSource API形成完整的技术方案。该技术能有效降低客户端等待时间,在智能对话系统、实时监控仪表盘等场景表现突出。实践中需特别注意连接管理、背压控制和JSON事件格

dixi7825的博客 393

【Java转AI实战】第3讲:流式输出——LLM的“分页查询“,附生产级SSE踩坑实录

本文是**「Java转AI实战」系列**的第3讲,共16讲。深入SSE协议和流式输出的生产级实现,包含完整前后端代码和真实生产项目的踩坑经验。

码农飞哥 509

Spring 中 SSE 流式输出的多种实现方式详解

SSE(Server-Sent Events)是一种允许服务器向浏览器推送实时数据的 Web 标准技术。它基于 HTTP 协议,使用单向通信:仅支持服务器向客户端推送数据基于 HTTP:无需特殊协议,兼容现有基础设施自动重连:内置断线重连机制事件 ID:支持事件标识和恢复与 WebSocket 相比,SSE 更简单易用,适合服务器推送场景(如 AI 对话流式输出、实时通知、数据监控等)。回到顶部项目技术栈:MVC 还是 WebFlux功能需求:是否需要背压、事件 ID 等特性团队熟悉度。

UzL2OrfFU的博客 257

Spring Boot SSE流式输出实战:AI对话场景下的高效实现方案

在实时数据推送和长任务处理场景中,传统的HTTP请求-响应模式面临用户体验差和请求超时等挑战。Server-Sent Events(SSE)作为一种基于HTTP的单向通信协议,通过将响应拆分为多个数据块实现持续推送,有效解决了这些问题。其技术价值在于复用现有HTTP基础设施,支持自动重连机制,特别适合服务器向客户端的单向数据流场景。在AI文本生成、实时通知和日志推送等应用场景中,SSE展现出显著优势。结合Spring WebFlux的响应式编程模型,开发者可以利用Flux组件优雅处理数据流,实现非阻塞I/O

weixin_31742871的博客 240

SSE 到底是什么?它和 HTTP 有什么关系?Java/Spring 怎么实现流式输出(可直接上手)

很多人第一次接触 `text/event-stream` 时会困惑:SSE 是不是一种新协议?为啥还要用 HTTP?为什么要心跳 ping?以及我在 Java 里为什么会遇到 `No converter ... text/event-stream` 这种报错?本文用“尽量通俗”的方式讲清楚 SSE 的底层逻辑,并给出 Spring MVC 里“代理/转发上游 SSE 流”的实现思路与可执行代码示例。

adru的博客 770

Spring Boot实现AI流式输出:SSE实战指南

流式输出是大语言模型(LLM)Web应用的核心交互范式,其本质是将模型逐token生成结果通过HTTP协议持续推送至前端。SSE(Server-Sent Events)作为W3C标准的单向长连接机制,凭借低内存开销、Nginx原生兼容、自动重连等特性,成为AI聊天、实时日志等场景下比WebSocket和轮询更优的工程选择。结合Spring Boot的SseEmitter与异步处理能力,可快速构建高并发、低延迟、易运维的流式API。本文聚焦SSE在AI服务中的协议细节、生命周期管理、Nginx配置及前端健壮性

weixin_29973493的博客 296

Java后端对接大模型流式输出:SSE协议原理与实战指南

流式输出是现代大模型应用中的核心交互方式,它解决了传统HTTP请求响应模式下用户长时间等待的体验痛点。其技术原理在于服务端通过SSE(Server-Sent Events)或WebSocket等协议,将生成结果分块实时推送给客户端,从而显著降低首字延迟并提升交互流畅性。对于Java后端开发者而言,掌握流式输出的本质——边读边传、及时flush、避免缓冲,是高效对接大模型API的关键。本文将结合SSE协议原理,深入讲解Java原生HttpClient如何读取流式响应,以及如何利用SseEmitter将数据实时

weixin_31528001的博客 300
上一篇: 结构化输出-让模型交回能用的JSON
Deng桑
博客等级 码龄1年 1粉丝 44原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值