Node.js上传文件中间件了解一下?
前言
Express中有各种上传文件的中间件,其中Multer的高效性值得我们去使用,他是Express官方推出的只用于处理multipart/form-data请求数据的中间件,但是官方文档中的说明并不是很清楚,对新手来说并不是特别友好,以下是我学习Multer的学习笔记,希望能给大家带来一些价值~
准备工作
1、创建一个文件夹multer_test,cd到该文件夹,输入以下命令新建工程,一路enter回车过去。
2、下载需要的安装包
1
| npm install express multer -save
|
3、根目录下新建app.js,输入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
var fs = require('fs'); var express = require('express'); var multer = require('multer');
var app = express(); app.get('/form', function(req, res, next){ var form = fs.readFileSync('./form.html', {encoding: 'utf8'}); res.send(form); });
app.listen(3009,function () { console.log("server at 3008 port"); });
|
4、根目录下创建form.html文件,输入代码:
1 2 3 4 5 6 7 8 9 10
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Multer</title> </head> <body> <h2>Multer Test</h2> </body> </html>
|
5、运行app.js,浏览器打开:http://localhost:3008/form
运行效果:

6、准备工作完成,开始coding吧~
Multer的使用
1、single(fieldname) - 单个文件上传
接收一个名为fieldname的上传文件,所上传的文件会被保存在req.file。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
var fs = require('fs'); var express = require('express'); var multer = require('multer');
var app = express();
var upload = multer({ dest: 'upload/'})
app.post('/upload-single',upload.single('logo'),function (req,res,next) { res.send('upload success!'); });
app.get('/form', function(req, res, next){ var form = fs.readFileSync('./form.html', {encoding: 'utf8'}); res.send(form); });
app.listen(3009,function () { console.log("server at 3008 port"); });
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Multer</title> </head> <body> <h2>Multer Test</h2> <form action="/upload-single" method="post" enctype="multipart/form-data"> <h3>单文件上传</h3> <input type="file" name="logo">
<input type="submit" value="提交"> </form> </body> </html>
|
upload.single(‘logo’)要和html中的input type=”file” name=”logo”要吻合,upload.single的功能是只上传单个文件,并且指定inpiut中的name。
在html中的form表单中enctype必须要为”multipart/form-data”,因为multer只处理multipart/form-data请求数据。

试试上传一个文件,会发现在根目录中多出了一个文件夹upload,里面还有一个二进制格式的文件,这就是我们上传的文件啦,二进制文件在一些环境下是打不开的,那我们怎么转换为正常格式的文件呢,不急,我们看下一步。

- 将二进制文件转换为普通文件:
打开app.js,修改post为:
1 2 3 4 5 6 7 8 9 10
| app.post('/upload-single',upload.single('logo'),function (req,res,next) { / 图片会放在uploads目录没有后缀,需要自己转存,用到fs模块 fs.rename(req.file.path, "upload/" + req.file.originalname, function(err) { if (err) { throw err; } }); res.send('upload success!'); });
|
重启app.js,再次上传文件,发现上传的文件已经带有后缀,转换成普通打得开的文件啦~
如图:

- 好啦,一个简单的multer上传文件例子完成啦,但是multer还有其他强大功能,我们接着往下看吧~
2、.array(fieldname,maxCount)-多文件上传
接收名为fieldname的,多个上传文件数组。可选参数maxCount表示可接受的文件数量,上传文件数超出该参数指定的数据后会抛出一个错误。文件数组会被保存在req.files数组中。
1 2 3 4 5 6 7 8 9 10 11 12 13
| app.post('/upload-array',upload.array('logo',3),function (req, res, next) { for (var i = 0; i < req.files.length; i++) { fs.rename(req.files[i].path, "upload/" + req.files[i].originalname, function(err) { if (err) { throw err; } }); console.log('文件'+(i+1)+'上传成功!'); } res.send('upload success!'); });
|
1 2 3 4 5 6 7 8
| <form action="/upload-array" method="post" enctype="multipart/form-data"> <h3>2.array(fieldname,maxCount)-多文件上传</h3>
文件1:<input type="file" name="logo"> <br> 文件2:<input type="file" name="logo"> <br> 文件3:<input type="file" name="logo"> <br> <input type="submit" value="提交"> </form>
|
- 多文件上传的req.files和单文件上传的req.file的区别是“s”,多文件就是files,单文件是file,千万不能弄混了。
- req.files是一个文件数组,所以要循环req.files[i];
上传文件:

上传结果:

其实这个array文件上传是有限制性的,我们注意到,在html中的表单中form的name=”logo”必须一致,也就是说在一个form中要上传多个文件,name必须是一致的,这在我们实际开发中显然达不到要求,那么有没有办法解决呢,当然有,别忘了,multer是强大的,往下面接着看吧~
3、fields(fields) - 多个文件上传(多域上传)
接收通过fields指定的多个上传文件。文件数组对象会被保存在req.files中。fields是一个包含对象的数组,对象中会包含name和maxCount两个属性:
1 2 3 4
| [ { name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 } ]
|
从fields的英文字义来看是“田野”的意思,我们顾名思义,一块田野中可以种植各种蔬菜,并且可以规定每种蔬菜的数量,那么name就是input标签中的name=‘’,maxCount就是form表单中每种文件上传的个数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| app.post('/upload-fields',upload.fields([{name:'logo',maxCount:2},{name:'logo2',maxCount:3}]),function (req, res, next) { for(var i = 0;i < req.files['logo'].length;i++){ fs.rename(req.files['logo'][i].path,'upload/'+req.files['logo'][i].originalname,function (err) { if(err){ throw err; } }); console.log('logo文件'+(i+1)+'上传成功!'); } for(var i = 0;i < req.files['logo2'].length;i++){ fs.rename(req.files['logo2'][i].path,'upload/'+req.files['logo2'][i].originalname,function (err) { if(err){ throw err; } }); console.log('logo2文件'+(i+1)+'上传成功!'); } res.send('upload success!'); });
|
1 2 3 4 5 6 7 8 9
| <form action="/upload-fields" method="post" enctype="multipart/form-data"> <h3>fields(fields) - 多个文件上传</h3> 1 <input type="file" name="logo"> <br> 2 <input type="file" name="logo"><br> 3 <input type="file" name="logo2"><br> 4 <input type="file" name="logo2"><br>
<input type="submit" value="提交"> </form>
|
1、fields(fields)中的参数与html中input标签中的name一一匹配
2、req.files[‘logo’]和req.files[‘logo2’]分别是连个文件数组,所以用两个for循环转存。
如图:

上传结果如图:

小伙伴们是不是觉得这种上传方式有点繁琐,那么没关系,下面还有一种文件上传方式,非常简便哦,我们一起来看吧
4、.any() - 接收所有文件上传
接收请求中的所有文件。上传文件数组会被保存在req.files中,这种方式没有多余的限制,比较便捷。
1 2 3 4 5 6 7 8 9 10 11 12 13
| app.post('/upload-any',upload.any(),function (req, res, next) { for (var i = 0; i < req.files.length; i++) { fs.rename(req.files[i].path, "upload/" + req.files[i].originalname, function(err) { if (err) { throw err; } }); console.log('文件'+(i+1)+'上传成功!'); } res.send('upload success!'); });
|
1 2 3 4 5 6 7
| <form action="/upload-any" method="post" enctype="multipart/form-data"> <h3>4.any() - 接收所有文件上传</h3> 文件1: <input type="file" name="logo"> <br> 文件2: <input type="file" name="logo"><br> 文件3: <input type="file" name="logo2"><br> <input type="submit" value="提交"> </form>
|
- 代码解读
1、文件数组保存在req.files中,与第二种上传方式一致
2、在html中input标签中不必要严格设置name的属性,比较便捷
- 重启app.js,运行
上传文件如图:

查看结果如图:

以上是multer四种上传文件的方式,以上例子都是比较简单的例子,在实际开发当中我们还有其他的要求,multer也给我们提供了这些API,我们接着往下看吧~
Multer其他“骚”操作
为了和上面的app.js区分开,我们新建一个test.js,输入以下代码,并且将端口改为3010:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
var fs = require('fs'); var express = require('express'); var multer = require('multer');
var app = express();
app.get('/form2', function(req, res, next){ var form = fs.readFileSync('./form2.html', {encoding: 'utf8'}); res.send(form); });
app.listen(3010,function () { console.log("server at 3010 port"); });
|
新建form2.html,输入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>Multer Other Test</h2> <form action="/upload-single" method="post" enctype="multipart/form-data"> <h3>Multer其他功能</h3> 文件1:<input type="file" name="logo"> <input type="submit" value="提交"> </form> </body> </html>
|
准备工作完成啦,我们来看看Multer还有其他哪些骚操作把~
1、文件对象
multer解析完上传文件后,会被保存为一个包含以下字段的对象:
| 属性 |
解释 |
| fieldname |
表单提交的文件名(input控件的name属性) |
| originalname |
文件在用户设备中的原始名称 |
| encoding |
文件的编码类型 |
| mimetype |
文件的Mime类型 |
| size |
文件的大小 |
| destination |
文件的保存目录(DiskStorage) |
| filename |
文件在destination中的名称(DiskStorage) |
| path |
上传文件的全路径(DiskStorage) |
| buffer |
文件对象的Buffer(MemoryStorage) |
那么问题来了,我们需要这些有什么用呢?当我们上传文件到后台以后,我们想要获得文件的详细数据与属性,我们就能通过这个来获得啦~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| var upload = multer({ dest: 'upload/'});
app.post('/upload-single',upload.single('logo'),function (req,res,next) {
fs.rename(req.file.path, "upload/" + req.file.originalname, function(err) { if (err) { throw err; } }); console.log('fieldname - 表单提交的文件名(input控件的name属性): '+req.file.fieldname); console.log('originalname - 文件在用户设备中的原始名称: '+req.file.originalname); console.log('encoding - 文件的编码类型: '+req.file.encoding); console.log('mimetype - 文件的Mime类型: '+req.file.mimetype); console.log('size - 文件的大小: '+req.file.size); console.log('destination - 文件的保存目录(DiskStorage): '+req.file.destination); console.log('filename - 文件在destination中的名称(DiskStorage): '+req.file.filename); console.log('path - 上传文件的全路径(DiskStorage): '+req.file.path); console.log('buffer - 文件对象的Buffer(MemoryStorage): '+req.file.buffer); res.send('upload success!'); });
|
1 2 3 4 5 6
| <h2>Multer Other Test</h2> <form action="/upload-single" method="post" enctype="multipart/form-data"> <h3>Multer其他功能</h3> 文件1:<input type="file" name="logo"> <input type="submit" value="提交"> </form>
|
2、选项参数
Multer的选项对象中可以包含以下值:
- dest或storage - 文件存储位置
- fileFilter - 函数,控制可上传的文件类型
- limits - 上传数据限制(文件大小)
1.storage - 存储引擎
.diskStorage(obj)与硬盘存储,该选项有以下两个可选项:
- destination - 硬盘存储,用于设置文件的存储目录,可以是一个函数或字符串。若未提供该参数,将使用系统的临时目录。
- filename - 内存存储,用于设置文件名。若未提供该参数,将使用一个随机字符串,且文件名中不包含扩展名。
示例:
1 2 3 4 5 6 7 8 9 10
| var storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, '/tmp/my-uploads') }, filename: function (req, file, cb) { cb(null, file.fieldname + '-' + Date.now()) } })
var upload = multer({ storage: storage })
|
我们可以使用这个来做什么呢?上面我解释四种文件上传方式的时候,每个post函数中都有一个用来转存文件的函数,显得非常臃肿,其实Multer早就为我们考虑到这一点了,我们开始codeing使用他吧~
注释以下代码:

在app.js中添加以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, './upload') }, filename: function (req, file, cb) { cb(null, file.originalname) } });
var upload = multer({ storage: storage });
app.post('/upload-single',upload.single('logo'),function (req,res,next) {
res.send('upload success!'); });
|
- 重启test.js,上传文件,发现效果和fs处理效果是一致的。
2.limits - 文件尺寸
该选项用于设置文件尺寸,Multer 会将这个对象传递至busboy中。limits对象中可以包含以下可选值:
| 参数 |
解释 |
| fieldNameSize |
字段名最大尺寸。默认值:100 bytes |
| fieldSize |
字段值最大尺寸。默认值:1MB |
| fields |
非文件字段的最大数量。默认值:Infinity |
| fileSize |
multipart 表单中,文件的最大尺寸。默认值:Infinity |
| files |
multipart 表单中,文件最大数量。默认值:Infinity |
| parts |
multipart 表单中,最大组件(fields+files)数量。默认值:Infinity |
| headerPairs |
默认值:2000 |
|
|
那么这些又有什么用呢?假设我们不想浪费服务器的流量,只允许客户端上传小于10MB的文件,那么我们就可以利用这个功能啦~
1 2
| //配制multer参数,设置上传的文件存储路径为upload,上传文件小于160kB,默认单位为B,所以160000B=160kB var upload = multer({ storage: storage,limits:{fileSize: 160000}});
|
- 重启test.js,上传文件,大于160kb的文件会显示上传失败
3.fileFilter - 文件筛选
fileFilter用于控制要哪些文件是可接受的,哪些是要被拒绝的。使用形式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function fileFilter (req, file, cb) {
cb(null, false)
cb(null, true)
cb(new Error('I don\'t have a clue!')) }
|
那么这个又有什么用呢,假设当上传的文件必须为统一格式,比如image的话,那我们就能用上这个功能啦~
1 2 3 4 5 6 7 8
| function fileFilter(req, file, cb){ const extension = file.mimetype.split('/')[0]; if(extension !== 'image'){ return cb(new Error('The file is not image type'), false); } cb(null, true); };
|
1 2
| var upload = multer({ storage: storage,limits:{fileSize: 160000000},fileFilter:fileFilter});
|
- 重启test.js,当上传其他格式文件时,显示上传错误
Multer中的几个“骚”操作我们差不多总结完啦,Multer是开发中非常常见的中间件,对于其掌握是非常必要的~
总结
- 因为官方文档对于multer解释不太清楚,小白看了会懵逼,所以才有了这一篇博文,希望能够帮助到一些刚刚入门Express的小伙伴们,也是自己巩固知识的好机会。
- 代码已经上传到GitHub啦,运行之前别忘记npm install哦,如果对你有帮助,给个star鼓励下啦~
- Nice to meet you ~