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

如何实现PHP逐词流式响应JS且不保留历史内容?

PHP到JS逐词流式传输的解决方案

PHP端关键调整

要避免响应内容累积,必须彻底关闭输出缓冲并强制实时输出:

  • 禁用PHP自身的输出缓冲:
    @ini_set('output_buffering', 'off');
    @ini_set('zlib.output_compression', 0);
    @ini_set('implicit_flush', 1);
    ob_end_clean(); // 清空已存在的缓冲区内容
    
  • 发送无缓存响应头,防止浏览器或中间服务器缓存内容:
    header('Content-Type: text/plain; charset=utf-8');
    header('Cache-Control: no-cache, no-store, must-revalidate');
    header('Pragma: no-cache');
    header('Expires: 0');
    
  • 逐词输出时强制刷新缓冲区:
    每次输出单个词后,必须调用ob_flush()和flush()确保内容立即发送到客户端,示例代码:
    $words = ['Hello', 'World', 'Streaming', 'Test'];
    foreach ($words as $word) {
        echo $word . "\n"; // 用换行作为新词分隔符,方便JS识别
        ob_flush();
        flush();
        sleep(1); // 模拟延迟,便于观察流式效果
    }
    

JS端流式处理

使用Fetch API监听响应流,每次仅读取新的输出片段,避免累积:

fetch('stream.php')
  .then(response => {
    const reader = response.body.getReader();
    const decoder = new TextDecoder('utf-8');
    
    function processChunk(result) {
      if (result.done) return;
      // 解码当前读取到的片段,提取新词(这里按换行分割)
      const chunk = decoder.decode(result.value, { stream: true });
      const newWords = chunk.trim().split('\n');
      newWords.forEach(word => {
        if (word) console.log('Received new word:', word);
      });
      return reader.read().then(processChunk);
    }
    
    return reader.read().then(processChunk);
  });

服务器端配置补充

如果使用Apache或Nginx,需禁用服务器级别的输出缓冲:

  • Apache:在.htaccess或虚拟主机配置中添加:
    SetEnv no-gzip 1
    php_flag output_buffering off
    
  • Nginx:在对应location块中添加:
    fastcgi_buffering off;
    proxy_buffering off;
    gzip off;
    

核心原因说明

之前出现内容累积,是因为PHP默认会缓冲输出内容(直到缓冲区满或脚本结束),部分服务器也会额外缓冲响应。只有彻底关闭各级缓冲,并在每次输出后强制刷新,才能实现逐词实时传输。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:08:12