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

如何正确实现Busboy?文件上传至Google Cloud Bucket遇报错求助

问题:使用FormData+Busboy上传文件到Google Cloud Bucket时遇到Unexpected end of form错误

我要把文件上传到Google Cloud Bucket,因为不太会处理文件,所以分步实现。现在尝试用FormData发送文件,再用Busboy解析,但遇到了node:events:498 throw er和Unexpected end of form at Multipart._final错误。以下是客户端、端点及服务器端代码,acceptedFiles数组来自react-dropzone组件,希望能得到帮助,我也可以提供更多说明。

客户端代码

const sendFile = async() =>{
  if(acceptedFiles.length > 0){
    for(let filePos = 0;filePos < acceptedFiles.length;filePos++){
      await sendToFireBase(acceptedFiles[filePos])
    }
  }else{
    window.alert("No files have been selected to be uploaded")
  }
}

端点代码

export default async function UploadToFireStorage(file){
  
    try{

        const formData = new FormData();
        formData.append(file.name,file);

        const response = await fetch(`http://localhost:5000/uploadNewFiles`,{
            method:"POST",
            body: formData
        })
    
        const jsonData = await response.json()
    
        console.log(jsonData)
  
    }catch(error){
  
        console.log(error)
  
    }
  
  }

服务器端代码

app.post('/uploadNewFiles',async(req,res)=>{

    console.log('made it to upload')

    try{
        
        if (req.method === 'POST') {
            const busboy = Busboy({ headers: req.headers });
        
            // This callback will be invoked for each file uploaded.
            busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
                try{
                    console.log('got the file');
                    res.json('File made it');
                }catch(error){
                    res.json('F')
                }
            });
        
            busboy.end(req.rawBody);
        } else {
            res.json('Not Post');
        }

    }catch(error){
        res.json("error: " + error)
        console.log(error)
    }

})

问题原因及修复方案

  1. 核心错误:请求体处理异常
    你调用busboy.end(req.rawBody)的方式有问题——如果Express应用提前用了express.json()/express.urlencoded()这类中间件,请求体已经被解析过,req.rawBody要么不存在,要么是不完整的截断数据,直接传给Busboy就会触发Unexpected end of form。另外,在file事件里直接返回res.json会提前关闭连接,导致表单流处理中断。

  2. 具体修复步骤

    • 给路由单独配置原始请求体解析
      跳过全局的表单解析中间件,给上传路由单独用express.raw处理multipart类型的请求:
      // 全局中间件保留,但给上传路由单独配置
      app.use(express.json());
      app.use(express.urlencoded({ extended: true }));
      
      app.post('/uploadNewFiles', express.raw({ type: 'multipart/form-data' }), async(req,res)=>{
          // 后续Busboy代码写在这里
      })
      
    • 让Busboy直接读取请求流
      不要手动调用busboy.end(req.rawBody),而是把请求流pipe给Busboy处理:
      app.post('/uploadNewFiles', express.raw({ type: 'multipart/form-data' }), async(req,res)=>{
          console.log('made it to upload');
          try{
              const busboy = Busboy({ headers: req.headers });
              // 处理文件流,这里可以直接pipe到Google Cloud Bucket
              busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
                  console.log(`收到文件:${filename}`);
                  // 示例:把文件流传到GCS
                  // const writeStream = cloudStorageBucket.file(filename).createWriteStream();
                  // file.pipe(writeStream);
              });
              // 所有文件处理完成后再返回响应
              busboy.on('finish', () => {
                  res.json('文件上传处理完成');
              });
              // 把请求流交给Busboy解析
              req.pipe(busboy);
          }catch(error){
              res.status(500).json(`错误:${error.message}`);
              console.error(error);
          }
      })
      
    • 修正客户端FormData字段名
      不要用动态的file.name当字段名,避免特殊字符导致解析异常:
      const formData = new FormData();
      // 固定字段名,比如'uploadedFile'
      formData.append('uploadedFile', file, file.name);
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 11:10:39