Multer 是一个用于处理 multipart/form-data
的 node.js 中间件,主要用于上传文件。它基于 busboy 构建,以实现最高效率。
注意:Multer 不会处理任何不是 multipart(multipart/form-data
)的表单。
此 README 也提供其他语言版本
$ npm install --save multer
Multer 将一个 body
对象和一个 file
或 files
对象添加到 request
对象中。body
对象包含表单文本字段的值,file
或 files
对象包含通过表单上传的文件。
基本用法示例
不要忘记在表单中添加 enctype="multipart/form-data"
。
<form action="/profile" method="post" enctype="multipart/form-data">
<input type="file" name="avatar" />
</form>
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {
// req.files is an object (String -> Array) where fieldname is the key, and the value is array of files
//
// e.g.
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body will contain the text fields, if there were any
})
如果您需要处理纯文本的多部分表单,则应使用 .none()
方法
const express = require('express')
const app = express()
const multer = require('multer')
const upload = multer()
app.post('/profile', upload.none(), function (req, res, next) {
// req.body contains the text fields
})
以下是如何在 HTML 表单中使用 multer 的示例。请特别注意 enctype="multipart/form-data"
和 name="uploaded_file"
字段
<form action="/stats" enctype="multipart/form-data" method="post">
<div class="form-group">
<input type="file" class="form-control-file" name="uploaded_file">
<input type="text" class="form-control" placeholder="Number of speakers" name="nspeakers">
<input type="submit" value="Get me the stats!" class="btn btn-default">
</div>
</form>
然后在您的 JavaScript 文件中,您将添加以下几行代码来访问文件和主体。重要的是,您在上传函数中使用表单中的 name
字段值。这告诉 multer 在请求中查找文件的哪个字段。如果这些字段在 HTML 表单和服务器上不相同,您的上传将失败
const multer = require('multer')
const upload = multer({ dest: './public/data/uploads/' })
app.post('/stats', upload.single('uploaded_file'), function (req, res) {
// req.file is the name of your file in the form above, here 'uploaded_file'
// req.body will hold the text fields, if there were any
console.log(req.file, req.body)
});
每个文件包含以下信息
键 | 描述 | 注意 |
---|---|---|
fieldname |
表单中指定的字段名称 | |
originalname |
用户计算机上的文件名 | |
encoding |
文件的编码类型 | |
mimetype |
文件的 MIME 类型 | |
size |
文件的大小(以字节为单位) | |
destination |
文件保存到的文件夹 | DiskStorage |
filename |
destination 中的文件名 |
DiskStorage |
path |
上传文件的完整路径 | DiskStorage |
buffer |
整个文件的Buffer |
内存存储 |
multer(opts)
Multer 接受一个选项对象,最基本的是 dest
属性,它告诉 Multer 将文件上传到哪里。如果你省略了选项对象,文件将保存在内存中,永远不会写入磁盘。
默认情况下,Multer 会重命名文件以避免命名冲突。重命名函数可以根据您的需要进行自定义。
以下是可以传递给 Multer 的选项。
键 | 描述 |
---|---|
dest 或 storage |
文件存储位置 |
fileFilter |
控制接受哪些文件的函数 |
limits |
上传数据的限制 |
preservePath |
保留文件的完整路径,而不是仅保留基本名称 |
在一个普通的 Web 应用程序中,可能只需要 dest
,并且可以像以下示例中所示进行配置。
const upload = multer({ dest: 'uploads/' })
如果你想要更多地控制你的上传,你应该使用 storage
选项而不是 dest
。Multer 附带了存储引擎 DiskStorage
和 MemoryStorage
;更多引擎可从第三方获得。
.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”的错误。
.any()
接受所有通过网络传输的文件。文件数组将存储在 req.files
中。
警告:确保你始终处理用户上传的文件。永远不要将 multer 作为全局中间件添加,因为恶意用户可能会将文件上传到你没有预料到的路由。仅在处理上传文件的路由上使用此函数。
storage
DiskStorage
磁盘存储引擎让你完全控制将文件存储到磁盘。
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
cb(null, file.fieldname + '-' + uniqueSuffix)
}
})
const upload = multer({ storage: storage })
有两个可用的选项,destination
和 filename
。它们都是用于确定文件存储位置的函数。
destination
用于确定应将上传的文件存储在哪个文件夹中。它也可以作为 string
(例如 '/tmp/uploads'
)给出。如果没有给出 destination
,则使用操作系统的默认临时文件目录。
注意: 当您提供 destination
作为函数时,您负责创建目录。当传递字符串时,multer 将确保为您创建目录。
filename
用于确定文件在文件夹中的名称。如果没有提供 filename
,则每个文件将被赋予一个随机名称,该名称不包含任何文件扩展名。
注意: Multer 不会为您附加任何文件扩展名,您的函数应返回包含文件扩展名的完整文件名。
每个函数都会传入请求 (req
) 和有关文件 (file
) 的一些信息,以帮助您做出决定。
请注意,req.body
可能尚未完全填充。这取决于客户端将字段和文件传输到服务器的顺序。
要了解回调中使用的调用约定(需要将 null 作为第一个参数传递),请参阅 Node.js 错误处理
内存存储
内存存储引擎将文件存储在内存中,作为 Buffer
对象。它没有任何选项。
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
使用内存存储时,文件信息将包含一个名为 buffer
的字段,该字段包含整个文件。
警告:上传非常大的文件,或在使用内存存储时,以非常快的速度上传大量相对较小的文件,会导致您的应用程序内存不足。
limits
一个对象,指定以下可选属性的大小限制。Multer 将此对象直接传递给 busboy,有关属性的详细信息可以在 busboy 的页面 上找到。
以下整数可用
键 | 描述 | 默认 |
---|---|---|
fieldNameSize |
最大字段名称大小 | 100 字节 |
fieldSize |
最大字段值大小(以字节为单位) | 1MB |
fields |
非文件字段的最大数量 | 无穷大 |
fileSize |
对于多部分表单,最大文件大小(以字节为单位) | 无穷大 |
files |
对于多部分表单,最大文件字段数量 | 无穷大 |
parts |
对于多部分表单,最大部分数量(字段 + 文件) | 无穷大 |
headerPairs |
对于多部分表单,要解析的最大标头键值对数量 | 2000 |
指定限制可以帮助保护您的网站免受拒绝服务 (DoS) 攻击。
fileFilter
将其设置为一个函数来控制哪些文件应该上传,哪些文件应该跳过。该函数应如下所示
function fileFilter (req, file, cb) {
// The function should call `cb` with a boolean
// to indicate if the file should be accepted
// To reject this file pass `false`, like so:
cb(null, false)
// To accept the file pass `true`, like so:
cb(null, true)
// You can always pass an error if something goes wrong:
cb(new Error('I don\'t have a clue!'))
}
遇到错误时,Multer 会将错误委托给 Express。您可以使用 标准的 Express 方法 显示一个友好的错误页面。
如果您想专门捕获来自 Multer 的错误,您可以自己调用中间件函数。此外,如果您只想捕获 Multer 错误,您可以使用附加到 multer
对象本身的 MulterError
类(例如 err instanceof multer.MulterError
)。
const multer = require('multer')
const upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
} else if (err) {
// An unknown error occurred when uploading.
}
// Everything went fine.
})
})
有关如何构建自己的存储引擎的信息,请参阅 Multer 存储引擎。