You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang后端+React前端SSE流式输出延迟问题求助

排查SSE打字机效果失效问题

后端Go代码排查

从你控制台一次性输出token的现象来看,优先排查后端流式响应的配置和处理逻辑:

  • 确认OpenAI流式调用开启:调用CreateChatCompletion时必须设置Stream: true,否则OpenAI会返回完整响应而非流式输出。核心配置示例:
req := openai.ChatCompletionRequest{
    Model:    openai.GPT3Dot5Turbo,
    Messages: messages,
    Stream:   true, // 必须开启此参数
}
  • 检查流式响应的发送逻辑:开启流式后,需要遍历ChatCompletionStream的返回通道,逐个发送token,同时强制刷新响应缓冲区,避免Go服务器缓冲内容。示例处理代码:
stream, err := client.CreateChatCompletionStream(ctx, req)
if err != nil {
    // 错误处理逻辑
}
defer stream.Close()

// 配置SSE响应头,缺一不可
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
w.Header().Set("Transfer-Encoding", "chunked")

// 初始化响应刷新器,确保内容实时发送
flusher, ok := w.(http.Flusher)
if !ok {
    http.Error(w, "Streaming not supported", http.StatusInternalServerError)
    return
}

for {
    response, err := stream.Recv()
    if errors.Is(err, io.EOF) {
        fmt.Fprintf(w, "data: [DONE]\n\n")
        flusher.Flush()
        break
    }
    if err != nil {
        fmt.Fprintf(w, "data: {\"error\":\"%s\"}\n\n", err.Error())
        flusher.Flush()
        break
    }
    // 提取单个token并按SSE格式发送
    token := response.Choices[0].Delta.Content
    if token != "" {
        fmt.Fprintf(w, "data: %s\n\n", token)
        flusher.Flush() // 强制刷新,避免服务器缓冲
    }
}
  • 排查中间件干扰:检查是否有日志、压缩类中间件对该路由启用了响应缓冲,这类中间件会把流式内容攒成整块输出,需要为/answer/api/v1/chat/completion路由跳过缓冲配置。

前端React代码排查

如果后端通过curl测试(curl -N http://你的服务器地址/answer/api/v1/chat/completion)能看到token逐个输出,再排查前端逻辑:

  • 正确监听SSE消息:确保在onmessage事件中实时更新UI,而非收集所有内容后再渲染。示例代码:
const [message, setMessage] = useState('');

useEffect(() => {
    const eventSource = new EventSource('/answer/api/v1/chat/completion');
    
    eventSource.onmessage = (event) => {
        if (event.data === '[DONE]') {
            eventSource.close();
            return;
        }
        // 实时追加token到现有内容
        setMessage(prev => prev + event.data);
    };

    eventSource.onerror = (error) => {
        console.error('SSE error:', error);
        eventSource.close();
    };

    return () => eventSource.close();
}, []);
  • 处理React状态批量更新:如果遇到状态更新延迟,可使用flushSync强制同步更新:
import { flushSync } from 'react-dom';

// 在onmessage事件内:
flushSync(() => {
    setMessage(prev => prev + event.data);
});
  • 排除开发工具干扰:检查是否有开发服务器插件、浏览器缓存插件导致响应被缓冲,可直接在无痕模式下测试。

核心注意事项

  • 后端必须保证Transfer-Encoding: chunked头正确设置,且每次发送token后调用flusher.Flush(),否则Go服务器会缓冲内容直到缓冲区满才发送。
  • SSE消息格式必须严格遵循data: 内容\n\n的规则,末尾的两个换行符是触发前端onmessage事件的关键。
  • 绝对不能在后端将所有token收集为字符串后一次性发送,这是流式效果失效的最常见原因。

内容的提问来源于stack exchange,提问作者jakelevirne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 19:56:07