nodejs文件上传处理模块formidable

GITHUB: https://github.com/felixge/node-formidable

在web开发中,经常遇到处理文件上传的情况。而express框架在4.0版本后就不在支持req.files接收上传文件,对于文件上传,需要加multipart格式数据处理的中间件。multipart数据处理中间件有:busboy, multer, formidable, multiparty,connect-multiparty, pez等。本站使用了formidable插件,比较简单易用。

formidable是一个用于处理文件、图片、视频等数据上传的模块,支持GB级上传数据处理,支持多种客户端数据提交。有极高的测试覆盖率,非常适合在生产环境中使用。

安装

formidable是一个轻量级的应用包,可以不依赖于express等框架单独使用,也可以集成到exress框架中使用。安装命令如下:

npm install formidable@latest

在nodejs原生环境中使用,需要手动下载模块后使用

git clone git://github.com/felixge/node-formidable.git formidable
vim my.js
# var formidable = require('./formidable');

使用

在nodejs原生环境中使用formidable。

var formidable = require('formidable'),
    http = require('http'),
    util = require('util');

//用http模块创建一个http服务端 
http.createServer(function(req, res) {
  if (req.url == '/upload' && req.method.toLowerCase() === 'post') {
    // 处理上传的文件
    var form = new formidable.IncomingForm();
 
    form.parse(req, function(err, fields, files) {
      res.writeHead(200, {'content-type': 'text/plain'});
      res.write('received upload:\n\n');
      res.end(util.inspect({fields: fields, files: files}));
    });
 
    return;
  }
 
  //显示一个用于上传的form
  res.writeHead(200, {'content-type': 'text/html'});
  res.end(
    '<form action="/upload" enctype="multipart/form-data" method="post">'+
    '<input type="text" name="title" /> '+
    '<input type="file" name="upload" multiple="multiple" /> '+
    '<input type="submit" value="Upload" />'+
    '</form>'
  );
}).listen(8080);

上传后,响应结果如下

received upload:

{ fields: { title: 'title的内容' },
  files:      //所有type="file"类型的数据对象
   { upload: 
      { domain: null,
        _events: {},
        _maxListeners: 10,
        size: 41966,             //文件大小
        path: '/var/folders/1k/86kq55_n4_q2tckwz9mb5wyr0000gn/T/upload_ecbf965abc1e14c2ffc86875c2f5eaa8',   //文件保存路径
        name: 'avatar.jpg',     //上传前的文件名
        type: 'image/jpeg',    //文件类型
        hash: null,
        lastModifiedDate: Sat May 16 2015 10:38:57 GMT+0800 (CST),
        _writeStream: [Object] } } }

常用API

创建一个incoming form实例

var form = new formidable.IncomingForm()

设置incoming form fields(fileds指除type=”file”外的其它接收数据)编码

form.encoding = 'utf-8';

设置文件接收后保存的文件夹。此文件夹一般为上传后的临时文件夹,上传后调用 fs.rename()对文件进行移动及重命名。默认保存路径为os.tmpDir()

form.uploadDir = "/my/dir";

设置上传后文件是否使用原扩展名,默认值为false。如果希望保存到form.uploadDir中的文件使用原扩展名时,需要将此项设置为true

form.keepExtensions = false;

‘multipart’或’urlencoded’类型的请求在formidable都支持,可通过上传文件的type属性查看文件类型

form.type

设置上传文件的大小,默认值为2M

form.maxFieldsSize = 2 * 1024 * 1024;

设置最大可接收字段数,用于防止内存溢出,默认值为1000

form.maxFields = 1000;

是否对上传文件进行hash较验,可设置为’sha1′ 或 ‘md5’

form.hash = false;

以上为常用的api,详细使用请参考其github:formidable

在express中使用formidable。

在express框架中使用formidable,需要一个接收文件提交的路由。以下示例为一个接收用户头像提交的路由

router.post("/user/avatar", user.avatar);

路由对应的接收提交数据的方法

//设置头像
exports.avatar = function(req, res, next) {
    var form = new formidable.IncomingForm();
    form.uploadDir = path.join(__dirname, 'tmp');   //文件保存的临时目录为当前项目下的tmp文件夹
    form.maxFieldsSize = 1 * 1024 * 1024;  //用户头像大小限制为最大1M  
    form.keepExtensions = true;        //使用文件的原扩展名
    form.parse(req, function (err, fields, file) {
        var filePath = '';
        //如果提交文件的form中将上传文件的input名设置为tmpFile,就从tmpFile中取上传文件。否则取for in循环第一个上传的文件。
        if(file.tmpFile){
            filePath = file.tmpFile.path;
        } else {
            for(var key in file){
                if( file[key].path && filePath==='' ){
                    filePath = file[key].path;
                    break;
                }
            }
        }
        //文件移动的目录文件夹,不存在时创建目标文件夹
        var targetDir = path.join(__dirname, 'upload');
        if (!fs.existsSync(targetDir)) {
            fs.mkdir(targetDir);
        }
        var fileExt = filePath.substring(filePath.lastIndexOf('.'));
        //判断文件类型是否允许上传
        if (('.jpg.jpeg.png.gif').indexOf(fileExt.toLowerCase()) === -1) {
            var err = new Error('此文件类型不允许上传');
            res.json({code:-1, message:'此文件类型不允许上传'});
        } else {
            //以当前时间戳对上传文件进行重命名
            var fileName = new Date().getTime() + fileExt;
            var targetFile = path.join(targetDir, fileName);
            //移动文件
            fs.rename(filePath, targetFile, function (err) {
                if (err) {
                    console.info(err);
                    res.json({code:-1, message:'操作失败'});
                } else {
                    //上传成功,返回文件的相对路径
                    var fileUrl = '/upload/' + fileName;
                    res.json({code:0, fileUrl:fileUrl});
                }
            });

            process.nextTick(function(){
                fs.unlink(filePath, function(err) {
                    if (err) {
                        console.info("删除上传时生成的临时文件失败");
                        console.info(err);
                    } else {
                        console.info("删除上传时生成的临时文件");
                    }
                });
            });
        }
    });
}

以上方法数据返回格式为json,客户端接收时可根据情况做相应处理。一个jQuery Ajax客户端上传示例请参考: jQuery文件上传插件jQuery Upload File 有上传进度条

12 thoughts on “nodejs文件上传处理模块formidable

  1. I know this if off topic but I’m looking into starting my
    own weblog and was wondering what all is needed to
    get set up? I’m assuming having a blog like yours
    would cost a pretty penny? I’m not very web smart so I’m not 100% positive.

    Any tips or advice would be greatly appreciated.
    Thanks

  2. Excellent post. I was checking constantly this blog and I am impressed!
    Extremely useful information particularly the last part :
    ) I care for such info much. I was looking for this particular info for a
    very long time. Thank you and good luck.

  3. Howdy! I could have sworn I’ve visited this web site before but
    after going through many of the posts I realized it’s new to me.

    Regardless, I’m definitely delighted I came across it and I’ll be
    bookmarking it and checking back often!

  4. Very nice info and straight to the point. I don’t know if this is in fact the best place to ask but do you folks have any thoughts on where to employ some professional writers? Thanks in advance 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *