在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原生环境中使用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;
}
上传后,响应结果如下
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;
在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});
}
});
}
});
}