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 Responses so far.

  1. Quest Bars says:
    Excellent post! We will be linking to this great content on our website.

    Keep up the good writing.

  2. 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

  3. Helpful info. Fortunate me I discovered your web site by chance, and I am
    shocked why this accident didn’t took place in advance!
    I bookmarked it.
  4. This info is priceless. How can I find out more?
  5. It’s really very complex in this full of activity life to
    listen news on TV, therefore I just use the web for that reason, and take the most recent news.
  6. 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.
  7. you’re truly a just right webmaster. The site loading pace is amazing.
    It seems that you’re doing any distinctive trick. Furthermore, The contents are masterpiece.

    you’ve performed a fantastic task on this topic!

  8. 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!

  9. What’s up Dear, are you in fact visiting this site on a
    regular basis, if so after that you will definitely
    obtain fastidious knowledge.
  10. I’m gone to tell my little brother, that he
    should also go to see this webpage on regular basis to take updated from
    newest gossip.
  11. Quality posts is the secret to be a focus for the users
    to pay a quick visit the website, that’s what this web site is
    providing.
  12. Edgar Katzen says:
    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 COMMENT