前端实现与Spring后端请求的实时流式响应,打造类 AI流式回复效果

在当今实时交互体验至上的时代,像ChatGPT那样流畅的流式回复体验越来越受欢迎。本文将深入浅出地讲解如何使用前端技术与Spring后端强强联手,打造令人惊艳的流式回复功能。

一、基本概念

在正式开始之前,我们先来了解一些基础概念:

  • 长连接: 区别于传统的HTTP请求-响应模式,长连接允许服务器主动向客户端推送数据,而无需等待客户端发起请求。
  • 流式传输: 数据并非一次性传输完毕,而是像流水一样持续地传输,让接收方可以实时处理。
  • WebSocket: HTML5提供的全双工通信协议,能够实现浏览器与服务器之间的双向实时通信。
  • SSE (Server-Sent Events): 服务端推送技术,浏览器通过HTTP连接接收服务器单向推送的数据流。
  • Spring WebFlux: Spring生态系统中用于构建反应式应用程序的框架,支持WebSocket和SSE,能够处理流式数据。

二、为什么需要实时流式响应

传统的HTTP请求-响应模式下,客户端必须不断地发送请求才能获取最新的数据,这种方式效率低下且资源消耗大。而长连接允许服务器主动推送数据,实时性更高,也更加节省资源。

三、技术选型与原理

1. 前端:

  • WebSocket: HTML5提供的全双工通信协议,完美契合长连接和流式数据传输的需求。
  • SSE (Server-Sent Events): 服务端推送技术,浏览器通过HTTP连接接收服务器单向推送的数据流。

2. 后端 (Spring):

  • Spring WebFlux: Spring生态系统中用于构建反应式应用程序的框架,支持WebSocket和SSE。

3. 原理:

  • 建立连接: 前端通过WebSocket或SSE与后端建立持久连接。
  • 发送请求: 前端发送消息请求到后端。
  • 流式处理: 后端接收请求后,不等待完整结果,而是将处理过程中的中间结果(例如逐字生成的回复)实时推送给前端。
  • 动态展示: 前端接收数据流,并动态更新页面内容,实现逐字显示的效果。

四、WebSocket方案实现

4.1 技术原理
  • 建立连接:
    • 前端使用 new WebSocket() 创建WebSocket对象,连接到后端指定的WebSocket地址。
    • 后端使用Spring WebFlux提供的 WebSocketHandler 接口处理WebSocket连接请求。
  • 数据传输:
    • 前端通过 WebSocket.send() 发送消息到后端。
    • 后端通过 WebSocketSession.send() 方法向客户端推送消息。
    • 前后端都可以监听 onmessage 事件来接收对方发送的消息。
  • 关闭连接:
    • 前端或后端都可以调用 WebSocket.close() 方法关闭连接。
4.2. 后端 (Spring WebFlux):
@Component
public class ChatWebSocketHandler implements WebSocketHandler {

    @Override
    public Mono<Void> handle(WebSocketSession session) {
        // 接收消息
        return session.receive()
                .map(WebSocketMessage::getPayloadAsText)
                .flatMap(message -> {
                    // 处理消息,例如调用ChatGPT API
                    return processMessage(message);
                })
                .flatMap(reply -> {
                    // 将回复逐字发送
                    return Flux.fromIterable(reply.split(""))
                            .delayElements(Duration.ofMillis(50)) // 模拟延迟
                            .map(session::textMessage)
                            .map(session::send);
                })
                .then(); 
    }

    // 模拟调用ChatGPT API并逐字返回回复
    private Mono<String> processMessage(String message) {
        return Mono.just("收到消息:" + message + ",正在思考中...").delayElement(Duration.ofSeconds(1))
                .flatMap(initialReply -> {
                    return Flux.range(0, initialReply.length())
                            .map(i -> initialReply.substring(0, i + 1))
                            .delayElements(Duration.ofMillis(100)) // 模拟逐字生成
                            .reduce((a, b) -> b) // 只取最后一个结果
                            .cast(String.class);
                });
    }
}
4.3. 前端 (JavaScript):
const socket = new WebSocket('ws://localhost:8080/chat');

socket.onopen = () => {
  console.log('WebSocket 连接已建立');
};

socket.onmessage = (event) => {
  const message = event.data;
  document.getElementById('chat-output').innerHTML += message; 
};

function sendMessage() {
  const message = document.getElementById('chat-input').value;
  socket.send(message);
}

五、SSE方案实现

4.1 技术原理
  • 建立连接: 前端使用 new EventSource() 创建EventSource对象,连接到后端指定的SSE接口。
  • 数据传输:
    • 后端通过 Flux<ServerSentEvent<T>> 返回数据流,Spring WebFlux会自动将数据流转换为SSE格式。
    • 前端监听 onmessage 事件接收后端推送的数据。
  • 关闭连接: 前端调用 EventSource.close() 关闭连接,或者后端停止发送数据。
4.2 代码示例

后端 (Spring WebFlux):

@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> streamEvents() {
    return Flux.interval(Duration.ofMillis(100))
            .map(sequence -> ServerSentEvent.<String>builder()
                    .data("数据流 - " + sequence)
                    .build());
}

前端 (JavaScript):

const eventSource = new EventSource('/stream');

eventSource.onmessage = (event) => {
  const message = event.data;
  document.getElementById('output').innerHTML += message + '<br>';
};

六、方案比较

特点 WebSocket SSE
连接类型 全双工 单向(服务器到客户端)
数据传输 双向 单向
应用场景 需要双向实时通信,如聊天、游戏 服务器推送数据,如实时更新、通知
复杂度 较高 较低

七、总结

本文只是大概介绍了如何利用WebSocket和SSE两种技术实现前端与Spring后端的长连接,并以ChatGPT的流式回复为例,给出了具体的代码实现和技术原理分析。

在实际应用中,需要根据具体需求选择合适的方案。如果需要双向实时通信,WebSocket是更优选择;如果只需服务器单向推送数据,SSE则更为轻量级。无论选择哪种方案,掌握长连接和流式数据处理都是构建现代化实时交互应用的关键。

希望本文能帮助你更好地入门去理解和应用实时流式响应技术,为用户打造更加流畅、自然的交互体验!

后续还会有更加深入去理解和实现技术!

相关推荐
组态软件3 小时前
web组态软件
前端·后端·物联网·编辑器·html
前端Hardy4 小时前
HTML&CSS:MacBook Air 3D 动画跃然屏上
前端·javascript·css·3d·html
小小李程序员6 小时前
LRU缓存
java·spring·缓存
cnsxjean6 小时前
SpringBoot集成Minio实现上传凭证、分片上传、秒传和断点续传
java·前端·spring boot·分布式·后端·中间件·架构
ZL_5676 小时前
uniapp中使用uni-forms实现表单管理,验证表单
前端·javascript·uni-app
kingbal7 小时前
SpringCloud:Injection of resource dependencies failed
后端·spring·spring cloud
沉浮yu大海7 小时前
Vue.js 组件开发:构建可重用且高效的 UI 块
前端·vue.js·ui
代码欢乐豆7 小时前
软件工程第13章小测
服务器·前端·数据库·软件工程
努力学习的啊张7 小时前
消息称三星正与 OpenAI 洽谈,有望令 Galaxy AI 整合ChatGPT,三星都要和chatgpt合作了,你会使用chatgpt了吗?
人工智能·chatgpt
莘薪8 小时前
JQuery -- 第九课
前端·javascript·jquery