express文件上传中间件Multer详解


Posted in Javascript onOctober 24, 2016

前言

Express默认并不处理HTTP请求体中的数据,对于普通请求体(JSON、二进制、字符串)数据,可以使用body-parser中间件。而文件上传(multipart/form-data请求),可以基于请求流处理,也可以使用formidable模块或Multer中间件。

1. multer中间件

Multer是Express官方推出的,用于Node.jsmultipart/form-data请求数据处理的中间件。

它基于busboy构建,可以高效的处理文件上传,但并不处理multipart/form-data之外的用户请求。

2. 安装

npm install multer --save

3. 使用

Multer在解析完请求体后,会向Request对象中添加一个body对象和一个file或files对象(上传多个文件时使用files对象 )。其中,body对象中包含所提交表单中的文本字段(如果有),而file(或files)对象中包含通过表单上传的文件。

基本使用示例如下:

var express = require('express')
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })

var app = express()

app.post('/profile', upload.single('avatar'), function (req, res, next) {
 // req.file 是 `avatar` 文件
 // req.body 对象中是表单中提交的文本字段(如果有)
})

app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
 // req.files 是 `photos` 文件数组
 // req.body 对象中是表单中提交的文本字段(如果有)
})

var cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {
 // req.files 是一个对象 (String -> Array),文件的字段名是其 key,文件数组是 key的值
 //
 // 如:
 // req.files['avatar'][0] -> File
 // req.files['gallery'] -> Array
 //
 // req.body 对象中是表单中提交的文本字段(如果有)
})

在使用中,如果仅需要处理multipart表单中的文本字段,可以使用multer中的.single() .array()fields()方法。

如,可以像下面这样使用.array()方法:

var express = require('express')
var app = express()
var multer = require('multer')
var upload = multer()

app.post('/profile', upload.array(), function (req, res, next) {
 // req.body 中包含文本字段
})

4. multer的API

4.1 文件对象

multer解析完上传文件后,会被保存为一个包含以下字段的对象:

       fieldname - 表单提交的文件名(input控件的name属性)

       originalname - 文件在用户设备中的原始名称

       encoding - 文件的编码类型

       mimetype - 文件的Mime类型

       size - 文件的大小

       destination - 文件的保存目录(DiskStorage)

       filename - 文件在destination中的名称(DiskStorage)

       path - 上传文件的全路径(DiskStorage)

       buffer - 文件对象的Buffer(MemoryStorage)

4.2 方法

multer(opts) - 创建对象

引用multer模块后,我们会获取到一个顶级方法。该方法是一个工厂函数,可以使用这个方法创建Multer对象。它接受一个选项对象,最基本的选项是dest,它告诉 Multer 文件的存储位置。如果忽略该选项,文件会被保存在内存中,并且永远不会写入硬盘中。

默认情况下,Multer会对文件进行重命令,以避免名称冲突。重命名函数,可以按需要自定义。

Multer的选项对象中可以包含以下值:

       dest或storage - 文件存储位置

       fileFilter - 函数,控制可上传的文件类型

       limits - 上传数据限制(文件大小)

在一般的Web应用中,只有dest选项需要设置。使用示例如下:

var upload = multer({ dest: 'uploads/' })

如果需要对上传文件做更多控制,可以使用storage代替dest,Multer会将存储引擎由DiskStorage(硬盘存储)切换为MemoryStorage(内存存储)。

创建multer对象后,我们可以使用以下实例来接收上传文件:

.single(fieldname) - 单个文件上传

接收一个名为fieldname的上传文件,所上传的文件会被保存在req.file。

.array(fieldname[, maxCount]) - 多个文件上传

接收名为fieldname的,多个上传文件数组。可选参数maxCount表示可接受的文件数量,上传文件数超出该参数指定的数据后会抛出一个错误。文件数组会被保存在req.files中。

.fields(fields) - 多个文件上传

接收通过fields指定的多个上传文件。文件数组对象会被保存在req.files中。

fields是一个包含对象的数组,对象中会包含name和maxCount两个属性:

[
 { name: 'avatar', maxCount: 1 },
 { name: 'gallery', maxCount: 8 }
]

.none() - 仅解析文本字段

仅解析文本字段。如果请求中有任何上传文件,会触发'LIMIT_UNEXPECTED_FILE'错误。这个方法与upload.fields([])类似。

.any() - 接收所有文件

接收请求中的所有文件。上传文件数组会被保存在req.files中。

4.3 选项参数

storage - 存储引擎

该选项有以下两个可选项:

       DiskStorage - 硬盘存储

       MemoryStorage - 内存存储

.diskStorage(obj)与硬盘存储

硬盘存储引擎提供了将文件存储到磁盘的完全控制:

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 })

.diskStorage()方法提供了文件存储位置控制权限,该方法接收一个对象参数,其中包含两destination和filename两个属性。

destination用于设置文件的存储目录,可以是一个函数或字符串。若未提供该参数,将使用系统的临时目录。

filename用于设置文件名。若未提供该参数,将使用一个随机字符串,且文件名中不包含扩展名。

.memoryStorage()与内存存储

内存存储引擎会以Buffer的形式将文件保存在内存中。该方法没有任何参数:

var storage = multer.memoryStorage()
var upload = multer({ storage: storage })

limits - 文件尺寸

该选项用于设置文件尺寸,Multer 会将这个对象传递至busboy中。limits对象中可以包含以下可选值:

       fieldNameSize - 字段名最大尺寸。默认值:100 bytes

       fieldSize - 字段值最大尺寸。默认值:1MB

       fields - 非文件字段的最大数量。默认值:Infinity

       fileSize - multipart 表单中,文件的最大尺寸。默认值:Infinity

       files - multipart 表单中,文件最大数量。默认值:Infinity

       parts - multipart 表单中,最大组件(fields+files)数量。默认值:Infinity

       headerPairs - 默认值:2000

fileFilter - 文件筛选

fileFilter用于控制要哪些文件是可接受的,哪些是要被拒绝的。使用形式如下:

function fileFilter (req, file, cb) {

 // 需要调用回调函数 `cb`,
 // 并在第二个参数中传入一个布尔值,用于指示文件是否可接受

 // 如果要拒绝文件,上传则传入 `false`。如:
 cb(null, false)

 // 如果接受上传文件,则传入 `true`。如:
 cb(null, true)

 // 出错后,可以在第一个参数中传入一个错误:
 cb(new Error('I don\'t have a clue!'))
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
JS正则中的RegExp对象对象
Nov 07 Javascript
Javascript在IE和FireFox中的不同表现简析
Dec 03 Javascript
Javascript实现滑块滑动改变值的实现代码
Apr 12 Javascript
IE8对JS通过属性和数组遍历解析不一样的地方探讨
May 06 Javascript
快速解决jquery之get缓存问题的最简单方法介绍
Dec 19 Javascript
JavaScript中的函数重载深入理解
Aug 04 Javascript
IE中鼠标经过option触发mouseout的解决方法
Jan 29 Javascript
js简单工厂模式用法实例
Jun 30 Javascript
微信小程序  简单实例(阅读器)的实例开发
Sep 29 Javascript
JS简单判断滚动条的滚动方向实现方法
Apr 28 Javascript
详解Vue前端生产环境发布配置实战篇
May 07 Javascript
Javascript异步流程控制之串行执行详解
Sep 27 Javascript
用js实现博客打赏功能
Oct 24 #Javascript
jQuery autoComplete插件两种使用方式及动态改变参数值的方法详解
Oct 24 #Javascript
jQuery插件实现可输入和自动匹配的下拉框
Oct 24 #Javascript
JS中split()用法(将字符串按指定符号分割成数组)
Oct 24 #Javascript
在js中实现邮箱格式的验证方法(推荐)
Oct 24 #Javascript
js实现上传文件添加和删除文件选择框
Oct 24 #Javascript
JS取数字小数点后两位或n位的简单方法
Oct 24 #Javascript
You might like
[EPIC] Larva vs Flash ZvT @ Crossing Field [2017-10-09]
2020/03/17 星际争霸
PHP用GD库生成高质量的缩略图片
2011/03/09 PHP
php设计模式 FlyWeight (享元模式)
2011/06/26 PHP
Laravel框架实现定时发布任务的方法
2018/08/16 PHP
javascript 处理事件绑定的一些兼容写法
2009/12/24 Javascript
用js解决数字不能换行问题
2010/08/10 Javascript
用jquery实现点击栏目背景色改变
2012/12/10 Javascript
js实现div弹出层的方法
2014/11/20 Javascript
在JavaScript中操作时间之getMonth()方法的使用
2015/06/10 Javascript
jQuery热气球动画半透明背景的后台登录界面代码分享
2015/08/28 Javascript
javascript高级编程之函数表达式 递归和闭包函数
2015/11/29 Javascript
JQuery获取鼠标进入和离开容器的方向
2016/12/29 Javascript
JS实现改变HTML上文字颜色和内容的方法
2016/12/30 Javascript
详解基于angular路由的requireJs按需加载js
2017/01/20 Javascript
Java中int与integer的区别(基本数据类型与引用数据类型)
2017/02/19 Javascript
js实现简单选项卡功能
2020/03/23 Javascript
Vue中computed、methods与watch的区别总结
2019/04/10 Javascript
react 不用插件实现数字滚动的效果示例
2020/04/14 Javascript
[02:24]DOTA2亚洲邀请赛 NAVI战队出场宣传片
2015/02/07 DOTA
[02:10]DOTA2 TI10勇士令状玩法及不朽Ⅰ展示:焕新世界,如你所期
2020/05/29 DOTA
Python线程的两种编程方式
2015/04/14 Python
基于python(urlparse)模板的使用方法总结
2017/10/13 Python
浅谈python3.6的tkinter运行问题
2019/02/22 Python
python如何编写win程序
2020/06/08 Python
python如何快速生成时间戳
2020/07/21 Python
分享一枚pycharm激活码适用所有pycharm版本我的pycharm2020.2.3激活成功
2020/11/20 Python
python3爬虫中多线程进行解锁操作实例
2020/11/25 Python
英国在线汽车和面包车零件商店:Car Parts 4 Less
2018/08/15 全球购物
SKECHERS斯凯奇中国官网:来自美国的运动休闲品牌
2018/11/14 全球购物
JACK & JONES荷兰官网:男士服装和鞋子
2021/03/07 全球购物
在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern "C"
2014/08/09 面试题
创建卫生先进单位实施方案
2014/03/10 职场文书
讲文明树新风演讲稿
2014/05/12 职场文书
2014年仓库管理工作总结
2014/12/17 职场文书
音乐教师个人总结
2015/02/06 职场文书
民间借贷被告代理词
2015/05/23 职场文书