笔者用nodejs作项目时须要用到文件上传的功能,在网上搜索了不少教程,找到了一个express的中间件,用于处理multipart/form-data
类型的表单数据,能够很方便的将表单中的文件数据保存到服务器。javascript
multer是一个node.js文件上传中间件,它是在 busboy的基础上开发的,上传的表单数据必须是multipart/form-data
类型,否则会报错。 html
Multer做为express的一个中间件,咱们能够很方便的自定义上传的文件目录以及保存的文件名。先看一个最简单的用法,demo1地址:java
var express = require('express');
var multer = require('multer');
var app = express();
var upload = multer({
storage: multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads/');
},
filename: function (req, file, cb) {
//file.originalname上传文件的原始文件名
var changedName = (new Date().getTime())+'-'+file.originalname;
cb(null, changedName);
}
})
});复制代码
咱们先建立了一个upload对象,这个对象中destination函数用来定义上传文件的存储的文件夹;filename函数用来修改上传文件存储到服务器的文件名称,这里咱们咱们加上一个时间戳简单区分一下。这两个函数都是经过回调函数来实现的。每次上传的时候这两个函数都会调用一次,若是是多个文件上传,那个这两个函数就调用屡次,调用顺序是先调用destination,而后调用filename。node
在两个函数中都会有一个file
对象,表示当前上传的文件对象,有如下几个属性:git
附:一些经常使用的MIME类型github
//单个文件上传
app.post('/upload/single',upload.single('singleFile'),(req,res)=>{
console.log(req.file);
res.json({
code: '0000',
type:'single',
originalname: req.file.originalname
})
});
//多个文件上传
app.post('/upload/multer',upload.array('multerFile'),(req,res)=>{
console.log(req.files);
let fileList = [];
req.files.map((elem)=>{
fileList.push({
originalname: elem.originalname
})
});
res.json({
code: '0000',
type:'multer',
fileList:fileList
});
});复制代码
在express中定义路由的回调函数时,把定义好了的upload对象做为中间件添加进去。若是是单个文件就用single
方法,若是是多个文件就用array
方法,这两个方法都须要传一个页面上定义好的字段名。express
在路由的回调函数中,request对象已经有了file属性(单个文件上传)或files属性(多个文件上传),files属性是一个数组,数组的每个对象都有如下属性:json
咱们能够发如今路由的回调函数中的file对象比diskStorage中的file对象多了几个属性,这是由于在diskStorage中文件尚未保存,只能知道文件的大体属性;而路由的回调函数文件已经在服务器上保存好了,文件的保存路径以及文件的大小都是已知的。数组
有时候咱们可能须要用字段名来对上传的文件进行一下划分,好比说上传多个图片的时候可能有身份证还有头像。虽然能够分开放到两个接口中,可是会产生其余一系列的麻烦事。multer支持对图片进行字段名的划分。demo3地址服务器
//多字段名上传
let multipleFields = upload.fields([
{name:'avatar'},
{name:'gallery', maxCount:3},
]);
app.post('/upload/fields', (req,res)=>{
multipleFields(req,res,(err) => {
console.log(req.files);
if(!!err){
console.log(err.message);
res.json({
code: '2000',
type: 'field',
msg:err.message
})
return;
}
var fileList = [];
for(let item in req.files){
var fieldItem = req.files[item];
fieldItem.map((elem) => {
fileList.push({
fieldname: elem.fieldname,
originalname: elem.originalname
})
});
}
res.json({
code: '0000',
type: 'field',
fileList: fileList,
msg:''
})
});
});复制代码
在这边也有req.files
属性,可是这个属性并非一个数组,而是一个复杂的对象,这个对象中有多个属性,每一个属性名都是一个字段名,每一个属性下面又是一个数组,数组下面才是一个个的文件对象,结构大体以下:
{
"avatar":[{
fieldname: "",
originalname: ""
//...
}],
"gallery":[{
fieldname: "",
originalname: ""
//...
}]
}复制代码
在文件上传时,有时候会上传一些咱们不须要的文件类型,咱们须要把一些不须要的文件给过滤掉。demo2地址。
var upload = multer({
//...其余代码
fileFilter: function(req, file, cb){
if(file.mimetype == 'image/png'){
cb(null, true)
} else {
cb(null, false)
}
}
});复制代码
在定义存储器的时候,新增一个fileFilter函数,用来过滤掉咱们不须要的文件,在回调函数中咱们传入true/false来表明是否要保存;若是传了false,那么destination函数和filename函数也不会调用了。
var upload = multer({
//...其余代码
limits:{
//限制文件大小10kb
fileSize: 10*1000,
//限制文件数量
files: 5
}
});复制代码
在定义存储器的时候,新增一个limits对象,用来控制上传的一些信息,它有如下一些属性:
在这边咱们把fileSize的值设置得小一点,设为10kb方便测试看效果,可是若是这个时候会发现有报错。由于上传的文件大小很容易就会超过10KB,致使有报错出现,咱们就须要在路由回调里对错误的状况进行捕获。
//单个文件上传
let singleUpload = upload.single('singleFile');
app.post('/upload/single',(req,res)=>{
singleUpload(req,res,(err)=>{
if(!!err){
console.log(err.message)
res.json({
code: '2000',
type:'single',
originalname: '',
msg: err.message
})
return;
}
if(!!req.file){
res.json({
code: '0000',
type:'single',
originalname: req.file.originalname,
msg: ''
})
} else {
res.json({
code: '1000',
type:'single',
originalname: '',
msg: ''
})
}
});
});
//多个文件上传
let multerUpload = upload.array('multerFile');
app.post('/upload/multer', (req,res)=>{
multerUpload(req,res,(err)=>{
if(!!err){
res.json({
code: '2000',
type:'multer',
fileList:[],
msg: err.message
});
}
let fileList = [];
req.files.map((elem)=>{
fileList.push({
originalname: elem.originalname
})
});
res.json({
code: '0000',
type:'multer',
fileList:fileList,
msg:''
});
});
});复制代码