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

如何实现XHR流式响应文本的逐块实时显示(类似ChatGPT)

流式文本逐块显示问题排查与修复

核心问题分析

你的代码逻辑本身没问题,但无法逐块输出通常是两个关键原因:

  • 后端未启用分块传输编码,浏览器会等待完整响应接收后才触发读取事件
  • 后端一次性输出所有内容,即使开启分块编码,也没有真正做到流式推送

修复后的前端代码

async read(url) {
    const response = await fetch(url, {
        method: "POST",
        headers: {
            "Content-Type": "text/plain",
        },
    });

    const data = response.body;
    if (!data) {
        return;
    }

    const reader = data.getReader();
    const decoder = new TextDecoder();
    let done = false;
    // 保留未完成解码的字节,处理多字节字符跨块的情况
    let leftover = new Uint8Array(0);

    while (!done) {
        const {value, done: doneReading} = await reader.read();
        done = doneReading;
        
        if (value) {
            // 合并剩余字节和当前块
            const combined = new Uint8Array(leftover.length + value.length);
            combined.set(leftover);
            combined.set(value, leftover.length);
            
            try {
                const text = decoder.decode(combined, {stream: true});
                console.log(text);
                leftover = new Uint8Array(0);
            } catch (e) {
                // 解码失败时,保留未完成的多字节字符部分
                leftover = combined.slice(Number(e.message.match(/index (\d+)/)[1]));
            }
        }
    }

    // 处理最后剩余的字节
    if (leftover.length > 0) {
        console.log(decoder.decode(leftover));
    }
}

后端必须配置的关键点

  • 强制设置响应头:Transfer-Encoding: chunked,明确告知浏览器这是分块响应
  • 后端要逐块输出内容并主动刷新缓冲区:比如Node.js中用res.write()替代res.end(),每次写入后调用res.flush();Java Servlet中调用response.flushBuffer()
  • 禁用会缓冲输出的中间件:部分压缩、缓存中间件会合并分块,导致流式推送失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 18:12:58