使用connect-busboy时如何捕获无文件上传的场景?
解决connect-busboy无文件上传的检测问题
我明白你的困扰——当没有文件上传时,busboy的file事件根本不会触发,靠文件大小判断自然行不通。其实核心思路是跟踪file事件是否被触发过,再结合finish事件(这个事件不管有没有文件都会触发)来统一处理后续逻辑。
下面是调整后的代码,我会一步步说明改动点:
const fs = require('fs'); // 假设你有邮件发送和验证的工具函数 const { sendEmailWithAttachment, sendEmailWithoutAttachment, validateEmailDetails } = require('./your-email-utils'); if (req.busboy) { // 标记是否有文件被上传 let hasAttachment = false; // 存储附件信息 let attachment = {}; // 跟踪文件上传的异步操作,确保文件写完再发邮件 let uploadPromises = []; // 收集邮件字段信息 let emailDetails = {}; req.busboy.on('field', function (fieldname, value) { console.log('Field [' + fieldname + ']: value: ' + value); // 把邮件相关字段存在emailDetails里,比如收件人、主题等 emailDetails[fieldname] = value; }); const now = (new Date).getTime(); req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) { // 只要触发file事件,就说明有文件上传 hasAttachment = true; const attachmentfile = '/tmp/' + now + '.' + filename; // 用Promise包裹文件写入逻辑,方便后续等待完成 const uploadPromise = new Promise((resolve, reject) => { const fstream = fs.createWriteStream(attachmentfile); file.pipe(fstream); fstream.on('close', function () { console.log("Upload Finished of " + filename); console.log('Time to upload: ' + utility.getFormattedTime((new Date).getTime() - now)); attachment.file = { 'name': filename, 'location': attachmentfile }; resolve(); }); // 处理文件写入错误 fstream.on('error', (err) => { console.error('File upload error:', err); reject(err); }); }); uploadPromises.push(uploadPromise); }); req.busboy.on('finish', async function () { // 第一步:先验证邮件字段是否合法 const isValid = validateEmailDetails(emailDetails); if (!isValid) { return res.error('Invalid email details, please check your input'); } try { // 等待所有文件上传完成(如果有文件的话) await Promise.all(uploadPromises); if (hasAttachment) { // 有附件:发送带附件的邮件 await sendEmailWithAttachment(emailDetails, attachment); return res.send('Email with attachment sent successfully'); } else { // 无附件:这里可以选择发送普通邮件,或者返回错误(根据你的业务需求) // 示例1:允许无附件发送 await sendEmailWithoutAttachment(emailDetails); return res.send('Email sent successfully without attachment'); // 示例2:不允许无附件,返回错误 // return res.error('No file attached, please upload an attachment'); } } catch (err) { return res.error('Failed to process request: ' + err.message); } }); // 关键:别忘了把请求流pipe给busboy,否则busboy不会解析任何事件 req.pipe(req.busboy); } else { res.error('Busboy is not initialized'); }
改动说明:
- 添加
hasAttachment标记:默认是false,只有当file事件触发时才设为true,这样就能在finish事件里判断是否有文件上传。 - 用Promise处理异步上传:文件写入是异步操作,
finish事件触发时文件可能还没写完,所以用Promise跟踪上传状态,确保邮件发送前文件已经保存完成。 - 统一逻辑到
finish事件:不管有没有文件,finish事件都会触发,在这里完成字段验证、文件状态判断和邮件发送,避免原来只有有文件时才执行发送逻辑的问题。 - 补充错误处理:添加了文件写入错误的捕获,避免请求挂起。
测试无文件上传的curl命令(示例):
curl -X POST \ http://localhost:3000/email/ \ -H 'Cache-Control: no-cache' \ -H 'content-type: multipart/form-data;' \ -F 'to=recipient@example.com' \ -F 'subject=Test No Attachment' \ -F 'body=This is a test email without attachment'
这样发送请求时,busboy不会触发file事件,hasAttachment保持false,就会进入无附件的处理逻辑啦。
内容的提问来源于stack exchange,提问作者Raghuveer
相关产品推荐
相关产品推荐

