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

使用Dicer处理异步multipart数据时如何将分片归类到对应文件

解决方法

Dicer本身的事件模型已经天然解决了分片归属的问题,不需要额外的全局标识字段,核心逻辑如下:

  • 每一次part事件回调拿到的p对象,对应一个独立的multipart分段(要么是普通表单字段,要么是一个完整的上传文件)
  • 同一个p对象触发的所有data事件返回的数据分片,都属于当前这个分段,不同分段的事件回调完全独立,不会出现分片交叉混乱的情况
  • 只需要利用JavaScript的函数作用域隔离每个part的上下文,就能把分片正确归类到所属文件

实现步骤

  1. 在part事件的回调作用域内,声明当前分段的专属存储变量(比如文件写入流、数据缓冲区、文件元信息等)
  2. 在header事件中解析Content-Disposition请求头,提取字段名、文件名,判断当前分段是否为上传文件
  3. 在当前part的data事件中,把收到的数据分片直接写入当前作用域对应的存储介质中
  4. 在当前part的end事件中完成文件收尾操作

示例代码

var inspect = require('util').inspect,
    http = require('http'),
    fs = require('fs'),
    path = require('path');
// 可使用content-disposition模块解析请求头,也可自行编写正则解析
var contentDisposition = require('content-disposition');

var Dicer = require('dicer');

var RE_BOUNDARY = /^multipart\/.+?(?:; boundary=(?:(?:"(.+)")|(?:([^\s]+))))$/i,
    HTML = Buffer.from('<html><head></head><body>\
                        <form method="POST" enctype="multipart/form-data">\
                         <input type="text" name="textfield"><br />\
                         <input type="file" name="filefield" multiple><br />\
                         <input type="submit">\
                        </form>\
                        </body></html>'),
    PORT = 8080,
    UPLOAD_DIR = path.join(__dirname, 'uploads'); // 上传文件存储目录

// 提前创建上传目录
if (!fs.existsSync(UPLOAD_DIR)) fs.mkdirSync(UPLOAD_DIR, { recursive: true });

http.createServer(function(req, res) {
  var m;
  if (req.method === 'POST'
      && req.headers['content-type']
      && (m = RE_BOUNDARY.exec(req.headers['content-type']))) {
    var d = new Dicer({ boundary: m[1] || m[2] });

    d.on('part', function(p) {
      // 当前part的专属变量,作用域隔离不会和其他part冲突
      let writeStream = null;
      let currentFileInfo = null;

      p.on('header', function(header) {
        // 解析content-disposition头
        const disposition = contentDisposition.parse(header['content-disposition'][0]);
        // 判断是文件类型的分段
        if (disposition.parameters.filename) {
          currentFileInfo = {
            fieldName: disposition.parameters.name,
            fileName: disposition.parameters.filename,
            savePath: path.join(UPLOAD_DIR, Date.now() + '_' + disposition.parameters.filename)
          };
          // 创建当前文件的写入流
          writeStream = fs.createWriteStream(currentFileInfo.savePath);
        }
      });

      p.on('data', function(data) {
        // 只有当前part是文件的时候才写入数据
        if (writeStream) writeStream.write(data);
        // 如果是普通表单字段可以把data拼到缓冲区自行处理
      });

      p.on('end', function() {
        if (writeStream) {
          writeStream.end();
          console.log('文件上传完成:', currentFileInfo);
        }
      });
    });

    d.on('finish', function() {
      console.log('所有分段处理完成');
      res.writeHead(200);
      res.end('Form submission successful!');
    });

    req.pipe(d);
  } else if (req.method === 'GET' && req.url === '/') {
    res.writeHead(200);
    res.end(HTML);
  } else {
    res.writeHead(404);
    res.end();
  }
}).listen(PORT, function() {
  console.log('Listening for requests on port ' + PORT);
});

注意事项

  • 大文件上传不要用Buffer拼接数据,直接用文件流写入可以避免内存溢出
  • 文件名要做重名处理,避免同名文件覆盖,示例中用时间戳做前缀就是这个目的
  • 生产环境建议增加文件大小、格式校验,避免恶意上传

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 00:24:02