# springboot_sse **Repository Path**: enzoism/springboot_sse ## Basic Information - **Project Name**: springboot_sse - **Description**: SpringBoot模拟大模型流式交互->【前端】+【后端】 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-03-05 - **Last Updated**: 2025-03-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SpringBoot-模拟SSE对话交互 > 后端使用SSE进行会话,前端使用Html模拟大模型的问答交互->【前端】+【后端】 ![](blob/模拟SSE对话交互.gif) -- -- ## 1-学习目的 ### 1-核心知识点 - 1)什么是SSE协议->客户端发起一次请求,服务器保持该连接打开,并在有新数据时主动向客户端推送 - 2)后端-开发SSE控制器 - 3)前端-如何与SSE协议交互 --- ### 2-附带知识点 - 1)什么是请求跨域-后端如何解决跨域问题 --- ## 2-动手实践 ### 1-什么是SSE协议 SSE(Server-Sent Events)协议是一种用于在 Web 浏览器和服务器之间实现服务器向客户端单向实时通信的技术。下面将从多个方面详细介绍 SSE 协议: #### 1-基本概念 SSE 允许服务器在建立连接后,持续向客户端发送更新信息。与传统的请求 - 响应模式不同,在 SSE 中,客户端发起一次请求,服务器保持该连接打开,并在有新数据时主动向客户端推送。 #### 2-工作原理 1. **建立连接**:客户端通过创建一个 `EventSource` 对象来向服务器发起 HTTP 请求,请求的响应头中包含 `Content-Type: text/event-stream`,表明这是一个 SSE 连接。 2. **服务器推送数据**:服务器保持连接打开,并在有新数据时,以特定的格式将数据发送给客户端。数据以文本流的形式传输,每条消息以两个换行符 `\n\n` 分隔。 3. **客户端接收数据**:客户端的 `EventSource` 对象会监听服务器发送的消息,并在接收到消息时触发相应的事件。 #### 3-消息格式 SSE 消息由多个字段组成,每个字段以键值对的形式表示,字段之间用换行符分隔。常见的字段有: - **`data`**:表示消息的实际内容。如果消息内容较长,可以分成多行,每行以 `data:` 开头。 - **`event`**:可选字段,用于指定事件类型。如果指定了事件类型,客户端可以针对不同的事件类型进行不同的处理。 - **`id`**:可选字段,用于为消息指定一个唯一的标识符。客户端可以使用这个标识符来实现消息的断点续传。 - **`retry`**:可选字段,用于指定客户端在连接中断后重试连接的时间间隔(以毫秒为单位)。 #### 4-优点和缺点 - **优点** - **简单易用**:客户端只需要创建一个 `EventSource` 对象,服务器端只需要按照特定的格式发送数据即可。 - **自动重连**:当连接中断时,客户端会自动尝试重新连接,并且可以使用 `id` 字段实现消息的断点续传。 - **浏览器原生支持**:现代浏览器都原生支持 `EventSource` 对象,无需额外的库或插件。 - **缺点** - **单向通信**:SSE 只支持服务器向客户端单向通信,客户端不能向服务器发送消息。 - **兼容性问题**:虽然现代浏览器都支持 SSE,但在一些旧版本的浏览器中可能不支持。 - **连接数量限制**:浏览器对每个域名的 SSE 连接数量有一定的限制,通常为 6 个。 #### 5-应用场景 - **实时新闻推送**:服务器可以实时向客户端推送最新的新闻消息。 - **股票行情更新**:服务器可以实时向客户端推送股票价格的变化。 - **在线聊天系统**:服务器可以实时向客户端推送新的聊天消息。 ---- ### 2-后端-开发SSE控制器-Java版本 #### 1. 编写SSE控制器 ```java 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.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @RestController public class ChatController { private final DeepSeekService deepSeekService; public ChatController(DeepSeekService deepSeekService) { this.deepSeekService = deepSeekService; } @GetMapping("/chat") public SseEmitter chat(@RequestParam String message) { SseEmitter emitter = new SseEmitter(); ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.submit(() -> { try { // 调用DeepSeek的chat模型 deepSeekService.streamChatResponse(message, emitter); } catch (Exception e) { emitter.completeWithError(e); } finally { executorService.shutdown(); } }); return emitter; } } ``` #### 2. 模拟DeepSeek服务 ```java import org.springframework.stereotype.Service; @Service public class DeepSeekService { public void streamChatResponse(String message, SseEmitter emitter) { // 调用DeepSeek的API并流式输出 try { // 模拟流式输出 String[] responses = {"Hello! ", "How can I help you? ", "I'm an AI assistant."}; for (String response : responses) { emitter.send(SseEmitter.event().data(response)); Thread.sleep(1000); // 模拟延迟 } } catch (Exception e) { emitter.completeWithError(e); } } } ``` ---- ### 3-前端:简单的HTML/JavaScript界面 #### 1. 创建一个前端页面 ```html DeepSeek Chat

DeepSeek Chat

``` ---- ## 3-其他版本SSE-NodeJs ### 1-服务器端代码示例(Node.js + Express) ```javascript const express = require('express'); const app = express(); app.get('/sse', (req, res) => { res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.flushHeaders(); let counter = 0; const intervalId = setInterval(() => { res.write(`data: Message ${counter}\n\n`); counter++; }, 1000); req.on('close', () => { clearInterval(intervalId); }); }); const port = 3000; app.listen(port, () => { console.log(`Server running on port ${port}`); }); ``` ### 2-客户端代码示例(JavaScript) ```html
``` ----