如何正确实现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) } })
问题原因及修复方案
核心错误:请求体处理异常
你调用busboy.end(req.rawBody)的方式有问题——如果Express应用提前用了express.json()/express.urlencoded()这类中间件,请求体已经被解析过,req.rawBody要么不存在,要么是不完整的截断数据,直接传给Busboy就会触发Unexpected end of form。另外,在file事件里直接返回res.json会提前关闭连接,导致表单流处理中断。具体修复步骤
- 给路由单独配置原始请求体解析
跳过全局的表单解析中间件,给上传路由单独用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
相关产品推荐
相关产品推荐

