Files
tuanwei-java/src/test/java/com/gxwebsoft/ai/controller/AiControllerSseFrameTest.java
T
weicw-dshsa bf6813e71d feat(ai): 聊天 WebSocket 加 /api 端点与心跳,WS 不可用时退到 HTTP SSE
生产网关在 /api 前丢掉 Upgrade 头,wss://…/chat/{userId} 到不了后端,
端上一直卡在「正在建立 WebSocket 连接…」。

- 新增 ApiChatWebSocketServer(/api/chat/{userId}),与老端点共用会话表;
  会话表改存 Session 而不是端点实例,两条路径都能收到推送
- 登记会话时关闭空闲超时(Tomcat 默认 20s,AI 首字慢时会被掐断),
  并补 @OnMessage 丢弃心跳(缺了它容器会因不支持的文本帧直接断连)
- send() 找不到 WS 会话时改投 ChatStreamRegistry,把帧送到 HTTP SSE 连接,
  推送侧仍只有 sendMessage 一个入口,三千多次调用点不用改
- prod 放开 com.gxwebsoft.ai.config 到 INFO:只保留连接/断开,推送路径仍静默
- 补 ChatStreamRegistryTest / WebSocketEndpointPathTest / AiControllerSseFrameTest

顺带补上 31eb75c 漏加的 ChatStreamRegistry.java:AiController 已经 import 它,
缺文件时 HEAD 编译不过。
2026-10-21 19:18:02 +08:00

50 lines
1.8 KiB
Java

package com.gxwebsoft.ai.controller;
import com.gxwebsoft.common.core.web.ApiResult;
import org.junit.jupiter.api.Test;
import java.util.LinkedHashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* SSE 末帧格式的回归测试。
*
* <p>出图这类「业务方法自己不推帧、只返回一个结果」的链路,结果靠末帧下发;
* 端上按 {@code type === 'final'} 识别。字段名一旦改了而端上没改,
* 表现为「流正常结束但页面一直转圈」,不容易在联调时发现,所以钉死格式。
*/
public class AiControllerSseFrameTest {
@Test
public void finalFrameMarksTypeAndKeepsResult() {
Map<String, Object> data = new LinkedHashMap<>();
data.put("photo_files", "[\"https://example.com/a.jpeg\"]");
String json = AiController.finalFrameJson(new ApiResult<>(0, "ok", data));
assertTrue(json.contains("\"type\":\"final\""), "末帧必须带 type=final,端上靠它区分业务帧");
assertTrue(json.contains("\"result\":{"), "业务返回值要原样放在 result 里");
assertTrue(json.contains("photo_files"), "返回体里的字段不能丢");
assertEquals(1, countOccurrences(json, "\"type\":"), "末帧只能有一个 type 字段");
}
@Test
public void finalFrameKeepsStringResult() {
String json = AiController.finalFrameJson("plain-text");
assertTrue(json.contains("\"result\":\"plain-text\""));
}
private static int countOccurrences(String text, String needle) {
int count = 0;
int index = text.indexOf(needle);
while (index != -1) {
count++;
index = text.indexOf(needle, index + needle.length());
}
return count;
}
}