响应式 API 与前端 ReadableStream
约 467 字大约 2 分钟
布欧-Lewyon
2026-06-08
首页 › Agent Spring Boot › WebFlux 与流式 API
Service 分层
agent-web-flux 虽简单,也建议 Controller 只做参数校验,逻辑放 Service——后面 agent-function-calling 会加 AgentService,结构一致。
ChatController → ChatService.streamChat()
→ (下一阶段)AgentService.agentChat()参数校验与提前返回
@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamChat(@RequestParam String message) {
if (message == null || message.isBlank()) {
return Flux.just("请输入有效问题", "[DONE]");
}
return chatService.streamChat(message);
}客户端断开
return chatService.streamChat(message)
.doOnCancel(() -> log.info("客户端断开 SSE"))
.doFinally(sig -> log.debug("流结束: {}", sig));超时
return chatService.streamChat(message)
.timeout(Duration.ofSeconds(120))
.onErrorResume(TimeoutException.class,
e -> Flux.just("生成超时,请重试", "[DONE]"));前端多会话与中止
agent-web-flux/frontend 已实现:
- Sidebar 多会话列表(纯前端 state)
- 每会话独立
AbortController,切换或删除时 abort 进行中的流 - Welcome 推荐问题卡片,点击即发起流式请求
- assistant 消息用
react-markdown+remark-gfm渲染
核心状态更新:
setMessages((prev) =>
prev.map((item) =>
item.id === assistantId
? { ...item, content: item.content + chunk }
: item
)
);CORS 与部署
开发期 ChatController 上 @CrossOrigin(origins = "*")。生产改为具体前端域名,或走 Nginx 同域反代。
单 jar 部署:
cd frontend && npm run build
./mvnw package -DskipTests
java -jar target/web-flux-0.0.1-SNAPSHOT.jar与下一阶段的衔接
agent-function-calling 在同样结构下新增:
| 端点 | 返回 | 用途 |
|---|---|---|
GET /api/chat/stream | Flux SSE | 纯聊天(保留) |
GET /api/agent/chat | Mono JSON | Agent + Tool |
前端 App.tsx 增加模式切换:聊天 vs Agent。
学习点
- 流式 API 保持薄 Controller;中止、超时在 Reactor 链处理。
- 前端流式 UI 三件套:ReadableStream、
AbortController、增量更新 state。 - 构建进
static/后无需单独部署前端。
小结
agent-web-flux完成流式骨架;下一阶段在同一工程加AgentService和/api/agent/chat。- 生产注意 SSE 缓冲、超时、CORS。
- 建议本地跑通
agent-web-flux再 clone 出agent-function-calling对照 diff。
上一节:WebClient 流式解析
下一节:Function Calling 协议
