fix(addon/aikefu): 修复EventSource有额外的空表数据输出,导致前端EventSource捕捉到error事件

This commit is contained in:
2025-12-10 14:21:52 +08:00
parent 7b6a8500b0
commit 357a479571
3 changed files with 34 additions and 9 deletions

View File

@@ -213,6 +213,8 @@ class Kefu extends BaseApi
if ($stream) { if ($stream) {
// 处理流式响应 // 处理流式响应
$this->handleStreamingResponse($url, $requestData, $headers, $message, $user_id); $this->handleStreamingResponse($url, $requestData, $headers, $message, $user_id);
// 流式响应处理完成后必须退出脚本,避免返回额外内容
exit;
} else { } else {
// 处理非流式响应 // 处理非流式响应
return $this->handleBlockingResponse($url, $requestData, $headers, $message, $user_id, $conversation_id); return $this->handleBlockingResponse($url, $requestData, $headers, $message, $user_id, $conversation_id);
@@ -617,12 +619,16 @@ class Kefu extends BaseApi
'content' => $assistant_content 'content' => $assistant_content
]; ];
echo "event: done\ndata: " . json_encode($done_data) . "\n\n"; echo "event: done\ndata: " . json_encode($done_data) . "\n\n";
// 发送连接关闭事件,让客户端知道连接已正常结束
echo "event: close\ndata: {\"status\":\"completed\"}\n\n";
// 只在有输出缓冲时才刷新 // 只在有输出缓冲时才刷新
if (ob_get_level() > 0) { if (ob_get_level() > 0) {
ob_flush(); ob_flush();
} }
flush(); flush();
$this->log('发送done事件会话ID' . $real_conversation_id, 'info'); $this->log('发送done和close事件会话ID' . $real_conversation_id, 'info');
// 保存助手的完整回复 // 保存助手的完整回复
if (!empty($real_conversation_id) && !empty($real_assistant_message_id) && !empty($assistant_content)) { if (!empty($real_conversation_id) && !empty($real_assistant_message_id) && !empty($assistant_content)) {
@@ -637,6 +643,9 @@ class Kefu extends BaseApi
$error_msg = 'AI客服请求异常' . $e->getMessage() . ',错误行:' . $e->getLine() . ',错误文件:' . $e->getFile(); $error_msg = 'AI客服请求异常' . $e->getMessage() . ',错误行:' . $e->getLine() . ',错误文件:' . $e->getFile();
$this->log($error_msg, 'error'); $this->log($error_msg, 'error');
} }
// 流式响应处理完成后必须退出脚本避免EventSource协议错误
exit;
} }
/** /**

View File

@@ -231,7 +231,7 @@
if (data.event === 'message_end') { if (data.event === 'message_end') {
statusText.textContent = '对话完成'; statusText.textContent = '对话完成';
sendBtn.disabled = false; // 不要在这里关闭连接等待done和close事件
} }
if (data.conversation_id) { if (data.conversation_id) {
@@ -257,16 +257,35 @@
} }
}); });
// 监听连接关闭事件
es.addEventListener('close', (event) => {
console.log('收到连接关闭事件:', event);
try {
const data = JSON.parse(event.data);
console.log('连接正常结束:', data);
if (es) {
es.close();
es = null;
}
} catch (error) {
console.error('解析关闭事件失败:', error);
}
});
// 监听错误事件 // 监听错误事件
es.addEventListener('error', (error) => { es.addEventListener('error', (error) => {
console.error('EventSource 错误:', error); console.error('EventSource 错误:', error);
// 添加更详细的错误信息 // 添加更详细的错误信息
if (es.readyState === EventSource.CLOSED) { if (es.readyState === EventSource.CLOSED) {
console.error('EventSource 连接已关闭'); console.log('EventSource 连接已正常关闭');
statusText.textContent = '连接已关闭';
} else if (es.readyState === EventSource.CONNECTING) { } else if (es.readyState === EventSource.CONNECTING) {
console.error('EventSource 连接中出现错误'); console.error('EventSource 连接中出现错误');
statusText.textContent = '连接错误';
} else {
console.error('EventSource 未知错误');
statusText.textContent = '连接错误';
} }
statusText.textContent = '连接错误';
sendBtn.disabled = false; sendBtn.disabled = false;
if (es) { if (es) {
es.close(); es.close();
@@ -274,11 +293,6 @@
} }
}); });
// 监听关闭事件
es.addEventListener('close', () => {
console.log('EventSource 连接关闭');
});
} catch (error) { } catch (error) {
console.error('创建 EventSource 失败:', error); console.error('创建 EventSource 失败:', error);
statusText.textContent = '请求失败'; statusText.textContent = '请求失败';

View File

@@ -365,6 +365,8 @@ class Kefu extends BaseApi
// 触发事件,让监听器处理流式响应 // 触发事件,让监听器处理流式响应
event('KefuChat', $event_data); event('KefuChat', $event_data);
// 流式响应需要终止脚本执行避免输出额外内容导致EventSource错误
exit;
} else { } else {
// 触发智能客服聊天事件(非流式) // 触发智能客服聊天事件(非流式)
$result = event('KefuChat', $event_data); $result = event('KefuChat', $event_data);