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

如何无需中间缓冲区将Busboy文件流附加到请求体?

使用Busboy处理表单文件流的优化方案

问题

我有一个使用busboy读取表单数据的Fastify插件,相关代码如下:

const bus = busboy({ headers: message.headers, limits: options });
bus.on("file", (fieldName: string, file: Readable, fileInfo: FileInfo) => {
    const chunks: Array<Uint8Array> = [];
    const fileObject = new File(fileInfo);
    fileObject.fieldName = fieldName;
    file.on("data", chunk => chunks.push(chunk));
    file.on("close", () => {
        fileObject.data = Readable.from(Buffer.concat(chunks));
        fileList.push(fileObject);
        formData[fieldName] = JSON.stringify(fileInfo);
    });
});

请问能否跳过file.on("data", chunk => chunks.push(chunk));和Readable.from(Buffer.concat(chunks))步骤,直接将file对象赋值给fileObject.data?我尝试过使用pipe等方法,但除非监听data事件,否则close事件不会触发,恳请解答!

解答

可以直接将file对象赋值给fileObject.data,核心问题是要让Busboy的文件流从暂停状态转为流动状态,这样才能触发close事件。以下是两种可行的实现方式:

方式1:调用resume()触发流流动

直接复用原文件流,调用resume()让流自动消费数据,即可正常触发close事件:

bus.on("file", (fieldName: string, file: Readable, fileInfo: FileInfo) => {
    const fileObject = new File(fileInfo);
    fileObject.fieldName = fieldName;
    // 直接赋值原可读流
    fileObject.data = file;
    // 启动流的流动,触发后续close事件
    file.resume();
    file.on("close", () => {
        fileList.push(fileObject);
        formData[fieldName] = JSON.stringify(fileInfo);
    });
});

注意:原可读流只能被消费一次,如果后续需要多次读取该流,你还是需要缓存chunk(即你最初的实现),或者使用stream-cache这类库给流添加缓存层。

方式2:通过空可写流消费数据

如果担心resume()可能导致数据丢失,也可以将流pipe到一个空的可写流中,同样能让流流动并触发close:

import { Writable } from 'stream';

bus.on("file", (fieldName: string, file: Readable, fileInfo: FileInfo) => {
    const fileObject = new File(fileInfo);
    fileObject.fieldName = fieldName;
    fileObject.data = file;
    // pipe到空可写流,消费流数据
    file.pipe(Writable({ write: () => {} }));
    file.on("close", () => {
        fileList.push(fileObject);
        formData[fieldName] = JSON.stringify(fileInfo);
    });
});

核心原理

Busboy生成的文件可读流默认处于暂停状态,只有当满足以下任一条件时,流才会开始推送数据:

  • 绑定了data事件监听
  • 调用了resume()方法
  • 被pipe到某个可写流
    只有流完成数据推送后,才会触发close事件。你之前直接赋值但没触发close,就是因为流一直处于暂停状态,没有被消费。

内容的提问来源于stack exchange,提问作者Mr. X

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 22:57:19