SSE连接持续触发onerror问题排查与修复咨询
问题修复方案
根据你提供的代码和问题描述,功能正常但客户端持续触发onerror,可以从以下几个方向排查修复:
1. 服务端响应头配置缺失(核心问题)
SSE对响应头有严格要求,你的Java代码中未设置必要的响应头,这是触发客户端错误的常见原因。修改服务端代码,为SseEmitter添加以下响应头:
public SseEmitter askStream(String prompt, Long cid) { final SseEmitter emitter = new SseEmitter(120000L); // 配置SSE必须的响应头 emitter.setContentType("text/event-stream;charset=UTF-8"); emitter.setHeader("Cache-Control", "no-cache"); emitter.setHeader("Connection", "keep-alive"); // 如果存在跨域请求,添加CORS头(根据实际场景调整) emitter.setHeader("Access-Control-Allow-Origin", "*"); emitter.setHeader("Access-Control-Allow-Headers", "x-access-token,x-request-id"); if (StringUtils.isBlank(prompt.trim())) { throw GlobalException.PARAM_VERIFY_EXCEPTION; } Long vipExpireTime = RequestContext.getVipExpireTime(); if (vipExpireTime == null || vipExpireTime <= System.currentTimeMillis()) { freeUserChat(emitter, prompt, cid); } else { askStreamImpl(emitter, prompt, cid); } return emitter; }
2. 服务端消息格式校验
确保服务端发送的消息符合SSE规范:每个消息必须以data: 开头,以两个换行符结尾。推荐使用SseEmitter.event()方法构造消息,避免手动拼接出错:
// 在freeUserChat或askStreamImpl中发送消息时 emitter.send(SseEmitter.event().data("推送的内容"));
3. 客户端错误处理逻辑优化
当前客户端一触发错误就直接关闭连接,可能误判正常的连接关闭(比如服务端主动结束推送)。同时,标准SSE没有onclose事件,你监听的onclose不会触发,导致无法正确识别连接结束状态,修改客户端代码:
export function doSseChatAsk(params: ChatAsk, onSseMessage: (msg: string) => void,) { let eventSource: EventSourcePolyfill; const accessToken = localStorage.getItem("x-access-token"); var queryString = Object.keys(params).map(key => key + '=' + params[key as keyof ChatAsk]).join('&'); eventSource = new EventSourcePolyfill('/ai/stream/chat/ask?' + queryString, { headers: { 'x-access-token': accessToken ?? "", 'x-request-id': uuid(), } }); eventSource.onopen = () => { console.log("SSE连接已建立"); } eventSource.onerror = (error) => { console.log("onerror", error); // 仅在连接异常时关闭,避免重复关闭已正常结束的连接 if (eventSource && eventSource.readyState !== EventSource.CLOSED) { eventSource.close(); } } eventSource.onmessage = e => { // 忽略心跳空消息(如果服务端配置了心跳) if (e.data.trim()) { onSseMessage(e.data); } }; eventSource.addEventListener('complete', () => { console.log('数据传输完成'); eventSource.close(); }); // 监听标准close事件,替换原有的onclose eventSource.addEventListener('close', () => { console.log('连接已关闭'); }); }
4. 超时与心跳优化
服务端设置的超时时间为120秒,若推送时间超过该时长会触发超时断开。可以通过添加心跳包避免:
在服务端askStream方法中添加定时心跳任务:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); // 每隔30秒发送一个空心跳包 scheduler.scheduleAtFixedRate(() -> { try { if (!emitter.isCompleted() && !emitter.isFailed()) { emitter.send(SseEmitter.event().data("")); } else { scheduler.shutdown(); } } catch (IOException e) { scheduler.shutdown(); } }, 30, 30, TimeUnit.SECONDS);
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

