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

Express.js能否分块发送响应?实测遇响应延迟显示问题

Express.js 分块发送响应数据的实现方法

Express.js 完全支持分块发送响应数据,你当前的代码没生效,主要是因为响应体缓冲未及时刷新,以及客户端对不完整JSON的渲染限制。以下是修正方案和说明:

问题分析

你代码里的res.flushHeaders()仅用于发送响应头,不会刷新响应体的缓冲。Express 默认会缓冲写入的数据,直到达到阈值或调用res.end()才会发送给客户端,导致浏览器和Postman要等完整响应才显示。

修正后的代码示例

const express = require('express');
const app = express();
const port = 3111;

const sleep = (ms) => {
  return new Promise((resolve) => setTimeout(resolve, ms));
};

app.get('/', async (req, res) => {
  // 明确启用分块传输(Express 也会自动识别,但手动设置更直观)
  res.setHeader('Transfer-Encoding', 'chunked');
  res.setHeader('Content-Type', 'application/json');

  // 发送JSON数组开头
  res.write('[');
  // 立即刷新缓冲,让客户端接收第一块数据
  res.flush();

  for (let i = 1; i <= 10; i++) { // 改为10条数据方便测试
    res.write(JSON.stringify(`data ${i}`));
    if (i < 10) {
      res.write(',');
    }
    // 每次写入后强制刷新缓冲,确保数据实时发送
    res.flush();
    await sleep(500);
  }

  res.write(']');
  res.end();
});

app.listen(port, () => {
  console.log(`App is live at http://localhost:${port}`);
});

关键调整点

  1. 调用res.flush():在每次res.write()后调用该方法(Express 4.16.0+支持),强制将缓冲中的数据发送给客户端,而不是等待缓冲满或响应结束。
  2. 分块传输头:虽然Express会自动在无Content-Length头时添加Transfer-Encoding: chunked,手动设置能更明确地启用分块传输。

客户端实时处理的优化方案

由于浏览器对不完整JSON的渲染限制(会等待完整结构才显示),如果需要客户端实时处理每一块数据,建议改用JSON Lines格式(每行一个JSON对象):

服务端代码

app.get('/stream', async (req, res) => {
  res.setHeader('Content-Type', 'application/x-ndjson');
  res.setHeader('Transfer-Encoding', 'chunked');

  for (let i = 1; i <= 10; i++) {
    // 每行输出一个JSON对象,用换行分隔
    res.write(JSON.stringify({ id: i, content: `data ${i}` }) + '\n');
    res.flush();
    await sleep(500);
  }
  res.end();
});

客户端处理代码

fetch('/stream')
  .then(res => {
    const reader = res.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';

    function processChunk() {
      reader.read().then(({ done, value }) => {
        if (done) return;
        buffer += decoder.decode(value);
        // 按换行分割数据行
        const lines = buffer.split('\n');
        buffer = lines.pop(); // 保留未完成的最后一行
        // 逐行解析JSON并处理
        lines.forEach(line => {
          if (line.trim()) {
            const data = JSON.parse(line);
            console.log('Received:', data);
          }
        });
        processChunk();
      });
    }

    processChunk();
  });

客户端工具的注意事项

  • Postman:默认会等待响应完成才展示结果,需在请求设置中开启「实时响应(Real-time response)」来查看分块数据。
  • Chrome:Network面板的「Response」标签可能不会实时更新,但「Raw」或「Preview」标签可以看到逐步接收的数据,也可以用上述客户端代码实时处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 09:17:02