Express后端拆分上传逻辑:如何将文件流传递至独立函数?
问题描述
前端通过FormData上传图片的代码:
const formData = new FormData(); formData.append('avatar', data.file); return API.post('/uploadImg', formData)
后端基于Express实现的原上传函数:
async function uploadImg(req, res) { req.pipe(req.busboy) req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) { const fstream = fs.createWriteStream(path.join("thestorage",`/image.${mimetype}` )) file.pipe(fstream) fstream.on('close', async (error, data) => { res.status(200).send({ message: 'Image was uploaded'}) }) } }
需求:拆分后端逻辑,让uploadImg仅负责处理请求响应,将文件管理逻辑独立为单独函数,询问如何把文件流传递到这个独立函数中。
当前尝试的代码:
async function uploadImg(req, res) { await theUpload(req.headers) res.status(200).send({ message: 'Image was uploaded'}) } async function theUpload(headers) { let bus_boy = new Busboy({headers: headers}) bus_boy.on('file', function (fieldname, file, filename, encoding, mimetype) { const fstream = fs.createWriteStream(path.join("thestorage",`/image.${mimetype}` )) file.pipe(fstream) fstream.on('close', async (error, data) => { console.log('done') }) } }
解决方案
1. 先封装独立的文件处理函数
把文件保存的逻辑抽成单独函数,用Promise包裹异步操作,方便后续等待执行完成:
const fs = require('fs'); const path = require('path'); // 独立的文件管理函数:接收文件流和元数据,处理文件保存 async function saveUploadedFile(file, filename, mimetype) { return new Promise((resolve, reject) => { // 生成唯一文件名,避免覆盖已有文件 const ext = mimetype.split('/')[1]; const filePath = path.join("thestorage", `${Date.now()}-${filename}.${ext}`); const writeStream = fs.createWriteStream(filePath); file.pipe(writeStream); writeStream.on('close', () => { console.log('文件保存完成'); resolve(filePath); // 可返回保存路径供后续使用 }); writeStream.on('error', (err) => { console.error('文件保存失败', err); reject(err); }); }); }
2. 重构请求处理与Busboy逻辑
在请求处理函数中解析请求流,触发Busboy的file事件时,直接把文件流传递给上面的独立函数,并等待操作完成后再返回响应:
const Busboy = require('busboy'); async function uploadImg(req, res) { try { await handleFileUpload(req); res.status(200).send({ message: 'Image was uploaded' }); } catch (err) { res.status(500).send({ message: '上传失败', error: err.message }); } } // 处理请求中的文件上传逻辑,调用独立的文件保存函数 async function handleFileUpload(req) { return new Promise((resolve, reject) => { const busboy = new Busboy({ headers: req.headers }); busboy.on('file', async (fieldname, file, filename, encoding, mimetype) => { try { await saveUploadedFile(file, filename, mimetype); resolve(); } catch (err) { reject(err); } }); busboy.on('error', (err) => { reject(err); }); // 必须将请求流pipe给busboy,才能解析FormData中的文件数据 req.pipe(busboy); }); }
关键说明
- 文件流传递:在Busboy的
file事件回调中,直接把获取到的file流(以及文件名、类型等元数据)传给独立的saveUploadedFile函数即可 - 异步控制:用Promise包裹所有异步操作,确保
uploadImg会等待文件完全保存后再返回响应,避免提前发送响应导致文件未处理完成 - 错误处理:添加全局错误捕获,在文件保存失败时返回错误响应,提升接口健壮性
内容的提问来源于stack exchange,提问作者Nikita Lvov
相关产品推荐
相关产品推荐

