前端实现与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则更为轻量级。无论选择哪种方案,掌握长连接和流式数据处理都是构建现代化实时交互应用的关键。

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

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

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰10 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪10 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪10 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy11 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom12 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom12 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试