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

Node.js Express返回流式数据客户端未按分块读取问题咨询

核心原因

你的流式传输逻辑本身符合规范,出现前端无法实时接收的问题,基本是中间环节存在缓冲导致的,常见原因如下:

  • 服务端启用了响应压缩中间件(如compression),默认会攒够一定大小的响应内容后才会压缩输出,阻断了实时分块返回
  • 缺少必要的响应头配置,导致浏览器/反向代理节点默认缓冲了响应内容
  • 部署架构中存在Nginx等反向代理,默认开启了上游响应缓冲,会等服务端返回完整响应后才发给浏览器
  • 客户端封装的wpeFetch存在全量读取响应的逻辑,没有透传流式可读对象
修复方案

服务端调整

在原有代码基础上修改响应头配置,同时关闭当前接口的压缩,修改后的服务端代码如下:

app.put('/api/action', (req, res) => { 
  const spawn = require('child_process').spawn; 
  // 关闭当前接口的压缩,避免compression中间件缓冲
  res.setHeader('Content-Encoding', 'identity');
  res.setHeader('Content-Type', 'text/plain; charset=utf-8'); 
  res.setHeader('Transfer-Encoding', 'chunked');
  // 禁止缓存和内容转换,避免中间节点缓冲
  res.setHeader('Cache-Control', 'no-cache, no-transform');
  res.setHeader('Connection', 'keep-alive');

  const child = spawn('./my-shell-script', [], { 
    cwd: path.resolve(__dirname, '../scripts/'), 
    shell: true 
  }); 

  child.stdout.on('data', data => { 
    const content = data.toString();
    console.log('write data', content); 
    res.write(content);
    // 可选:手动刷出响应缓冲,确保内容立即发送
    res.flush?.();
  }); 

  child.stderr.on('data', error => { 
    const errContent = error.toString();
    console.log('write error', errContent); 
    res.write(errContent);
    res.flush?.();
  }); 

  child.on('error', s => console.error('error', s)); 
  child.on('close', (code) => { 
    console.log(`action exited with code ${code}`); 
    if (code !== 0) { 
      res.status(500); 
    } 
    res.end(); 
  }); 
});

反向代理配置调整(存在Nginx部署场景)

在接口对应的Nginx location配置段中添加以下规则,关闭代理缓冲:

location /api/action {
  proxy_pass http://你的Express服务地址;
  proxy_buffering off;
  proxy_set_header Connection keep-alive;
}

客户端验证调整

先替换wpeFetch为原生fetch测试流式接收是否正常,如果原生fetch可以正常逐块打印内容,说明你封装的wpeFetch内部做了全量读取响应的逻辑,需要修改封装逻辑透传response.body可读流。
原生fetch测试代码如下:

const response = await fetch(`/api/action`, { 
  method: 'PUT', 
  headers: new Headers({ 
    'Content-Type': 'application/json' 
  }), 
  body: JSON.stringify({ scope: site, action, }) 
}); 

const reader = response.body.pipeThrough(new window.TextDecoderStream()).getReader(); 
while (true) { 
  const { value, done } = await reader.read(); 
  if (done) break; 
  console.log('Received', value); 
} 
console.log('Response fully received');

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 10:36:01