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

如何将Node.js spawn子进程的stdout作为Fastify API流式响应返回

你当前代码的核心问题是将所有子进程输出缓存到变量中,等到子进程退出后才一次性返回,要实现实时逐段返回需要直接将子进程的输出流和HTTP响应流绑定,逐块写入响应。

修改后的完整代码

const fastify = require("fastify")({ logger: true });
const { spawn } = require("child_process");
const bat = require.resolve("./run.bat");

// 声明路由
fastify.post("/", (request, reply) => {
  const { agent, sub, location, times } = request.body;
  if (!agent) {
    return reply.code(400).send({ msg: "缺少必填参数agent" });
  }

  // 设置流式响应头
  reply.header("Content-Type", "text/plain; charset=utf-8");
  reply.header("Cache-Control", "no-cache");
  reply.header("Connection", "keep-alive");
  reply.header("Transfer-Encoding", "chunked");

  // Windows环境运行bat建议加shell: true参数,避免执行报错
  const ls = spawn(bat, [agent, sub, location, times], { shell: process.platform === 'win32' });
  
  ls.stdout.setEncoding("utf8");
  ls.stdout.on("data", (data) => {
    console.log("stdout: " + data);
    // 实时写入响应流
    reply.write(data.toString());
  });

  ls.stderr.setEncoding("utf8");
  ls.stderr.on("data", (data) => {
    console.log("stderr: " + data);
    // 错误输出也实时写入响应
    reply.write(data.toString());
  });

  ls.on("exit", (code) => {
    console.log("子进程退出,退出码: " + code);
    // 结束响应
    reply.end();
  });

  // 监听子进程错误,避免服务崩溃
  ls.on("error", (err) => {
    console.error("子进程执行出错: ", err);
    reply.write(`执行错误: ${err.message}\n`);
    reply.end();
  });
});

// 启动服务
const start = async () => {
  try {
    await fastify.listen(3000, "0.0.0.0");
  } catch (error) {
    fastify.log.error(error);
    process.exit(1);
  }
};
start();

关键修改说明

  • 移除了路由handler的async修饰符,采用手动控制响应流的模式,避免Fastify自动等待返回值提前结束响应
  • 预先设置流式响应头,告知客户端该响应为分块传输,不要等待全部内容加载完成再展示
  • 子进程的stdout、stderr收到数据时直接写入响应流,不需要缓存到变量
  • 子进程退出或报错时调用reply.end()主动结束响应,代替原来的一次性reply.send
  • 新增子进程错误监听,避免执行异常时服务崩溃,同时补充了参数缺失时的响应逻辑
  • 新增Windows平台兼容配置,运行bat时自动开启shell模式,避免系统找不到bat执行程序的问题

测试提示

如果使用Postman测试默认会等待全部响应完成再展示内容,可以用curl命令直接测试,即可看到实时逐段输出的效果:
curl http://localhost:3000 -X POST -H "Content-Type: application/json" -d '{"agent":"test","sub":"test","location":"test","times":"1"}'

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 04:06:01