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

使用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');
}

改动说明:

  1. 添加hasAttachment标记:默认是false,只有当file事件触发时才设为true,这样就能在finish事件里判断是否有文件上传。
  2. 用Promise处理异步上传:文件写入是异步操作,finish事件触发时文件可能还没写完,所以用Promise跟踪上传状态,确保邮件发送前文件已经保存完成。
  3. 统一逻辑到finish事件:不管有没有文件,finish事件都会触发,在这里完成字段验证、文件状态判断和邮件发送,避免原来只有有文件时才执行发送逻辑的问题。
  4. 补充错误处理:添加了文件写入错误的捕获,避免请求挂起。

测试无文件上传的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:02:11