一、概念
Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。 注意: Multer 不会处理任何非 multipart/form-data 类型的表单数据。
二、安装
npm i multer --save
三、使用(页面底部有单文件、多文件上传案例)
Multer 会在express 的 request 对象里添加一个 body 对象 (包含表单的文本域信息)以及 file 或 files 对象 (单文件通过req.file获取,多文件通过req.files获取,file 或 files 对象包含对象表单上传的文件信息)。
四、基本使用
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single(fielname), function (req, res, next) {
})
app.post('/photos/upload', upload.array(fielname, 12), function (req, res, next) {
})
const cpUpload = upload.fields([{ name:fields[, maxCount: 1 ]}, { name: 'gallery', maxCount: 8 }])
app.post('/profile', upload.none(), function (req, res, next) {
})
五、文件对象
后端接收到的文件对象,文件对象的接收见上一步 每个文件具有下面的信息
Key | Description | Note |
---|
fieldname | Field name 由表单指定(前后端一致) | | originalname | 用户计算机上的文件的名称 | | encoding | 文件编码 | | mimetype | 文件的 MIME 类型 | | size | 文件大小(字节单位) | | destination | 保存路径 | DiskStorage | filename | 保存在 destination 中的文件名 | DiskStorage | path | 已上传文件的完整路径 | DiskStorage | buffer | 一个存放了整个文件的 Buffer | MemoryStorage |
打印一下
六、配置参数options
Multer 接受一个 options 对象,其中最基本的是 dest 属性(一般情况下使用dest就可以了),这将告诉 Multer 将上传文件保存在哪。如果你省略 options 对象,这些文件将保存在内存中,永远不会写入磁盘。
为了避免命名冲突,Multer 会修改上传的文件名。这个重命名功能可以根据您的需要定制。 重命名可以通过new Date().getTime()拼接保证不重复。 如:file.filename.slice(0, 10) + new Date().getTime() + '.' + hou (hou——文件后缀名的截取,也可以自己配置)
以下是可以传递给 Multer 的选项。
Key | Description |
---|
dest or storage | 在哪里存储文件 | fileFilter | 文件过滤器,控制哪些文件可以被接受 | limits | 限制上传的数据 | preservePath | 保存包含文件名的完整文件路径 |
6.1storage存储引擎
加强对文件上传的更多控制
6.1.1磁盘存储引擎(DiskStorage)
磁盘存储引擎可以让你控制文件的存储
```javascript
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({ storage: storage })
有两个选项可用,destination 和 filename 。他们都是用来确定文件存储位置的函数。
destination 是用来确定上传的文件应该存储在哪个文件夹中。也可以提供一个 string (例如 '/tmp/uploads' )。如果没有设置 destination ,则使用操作系统默认的临时文件夹。
注意: 如果你提供的 destination 是一个函数,你需要负责创建文件夹。当提供一个字符串,multer 将确保这个文件夹是你创建的。
filename 用于确定文件夹中的文件名的确定。 如果没有设置 filename ,每个文件将设置为一个随机文件名,并且是没有扩展名的。
注意:Multer 不会为你添加任何扩展名,你的程序应该返回一个完整的文件名。
每个函数都传递了请求对象 (req ) 和一些关于这个文件的信息 (file ),有助于你的决定。
注意 req.body 可能还没有完全 填充,这取决于向客户端发送字段和文件到服务器的顺序
6.1.2内存存储引擎(MemoryStorage)
内存存储引擎将文件存储在内存中的 Buffer 对象,它没有任何选项。
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
当使用内存存储引擎,文件信息将包含一个 buffer 字段,里面包含了整个文件数据。
警告: 当你使用内存存储,上传非常大的文件,或者非常多的小文件,会导致你的应用程序内存溢出。
6.2fileFiter(文件过滤器)
设置一个函数来控制什么文件可以上传以及什么文件应该跳过,这个函数应该看起来像这样:
```javascript
function fileFilter (req, file, cb) {
// 这个函数应该调用 `cb` 用boolean值来
// 指示是否应接受该文件
// 拒绝这个文件,使用`false`,像这样:
cb(null, false)
// 接受这个文件,使用`true`,像这样:
cb(null, true)
cb(new Error('I don\'t have a clue!'))
}
6.3limits(限制上传的数据)
一个对象,指定一些数据大小的限制。
Key | Description | Default |
---|
fieldNameSize | field 名字最大长度 | 100 bytes | fieldSize | field 值的最大长度 | 1MB | fields | 非文件 field 的最大数量 | 无限 | fileSize | 在 multipart 表单中,文件最大长度 (字节单位) | 无限 | files | 在 multipart 表单中,文件最大数量 | 无限 | parts | 在 multipart 表单中,part 传输的最大数量(fields + files) | 无限 | headerPairs | 在 multipart 表单中,键值对最大组数 | 2000 |
七、错误处理机制
当遇到一个错误,multer 将会把错误发送给 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) {
} else if (err) {
}
})
})
八、单文件上传案例
app.js基本配置
const express = require('express')
const morgan = require('morgan')
const favicon = require('serve-favicon')
const path = require('path')
const router = require('./router/router')
const app = express()
app.use(express.static(__dirname + '/public'))
app.use(favicon(path.join(__dirname, 'public', 'img', '1.jpg')))
app.use(express.urlencoded({ 'limit': '10mb', 'extended': true }))
app.use(express.json({ 'limit': '10mb' }))
app.use("/api", router)
app.listen(8000, (req, res) => {
console.log('服务已经运行\nhttp://127.0.0.1:8000\nhttp://localhost:8000');
})
router.js
const express = require('express')
const multer = require('multer')
const path = require('path')
const router = express.Router()
const storage = multer.diskStorage({
destination: function(req, res, cb) {
cb(null, './public/uploads')
},
filename: function(req, file, cb) {
let fileData = Date.now() + "-" + Math.round(Math.random() * 1e9) + path.extname(file.originalname);
cb(null, file.fieldname + "-" + fileData)
}
})
const upload = multer({
storage: storage
})
router.post('/upload', upload.single('file'), (req, res) => {
console.log(req.file);
console.log(req.body);
res.json({
code: 0,
msg: "ok"
})
})
module.exports = router
前端 html
<body>
<form id="xcgg_yyds">
<input type="file" id="xcgg" accept=".png,.jpeg,.jpg,.gif">
</form>
</body>
js
$('#xcgg').on('change', function() {
console.log(this.files);
let fileObject = this.files[0]
let myFormData = new FormData()
myFormData.append('file', fileObject)
myFormData.append('name', 'xcgg')
$.ajax({
url: 'http://127.0.0.1:8000/api/upload',
type: 'post',
contentType: false,
processData: false,
data: myFormData,
success(res) {
console.log(res);
}
})
})
效果
九、多文件上传案列
html
<body>
<form id="xcgg_yyds">
<input type="file" id="xcgg" accept=".png,.jpeg,.jpg,.gif" multiple>
</form>
</body>
js
$('#xcgg').on('change', function() {
let fileObjects = this.files
let myFormData = new FormData()
myFormData.append('files', fileObjects)
for (let i = 0; i < fileObjects.length; i++) {
myFormData.append('files', fileObjects[i])
}
myFormData.append('name', 'xcgg')
$.ajax({
url: 'http://127.0.0.1:8000/api/upload',
type: 'post',
contentType: false,
processData: false,
data: myFormData,
success(res) {
console.log(res);
}
})
})
后端 拦截请求不同,其他都相同
router.post('/upload', upload.array('files', 3), function(req, res, next) {
let files = req.files
console.log(req.files);
if (files.length === 0) {
res.json({
code: 500,
msg: '文件上传不能为空'
})
return
} else {
res.json({
code: 0,
msg: '上传成功',
data: files
})
}
})
效果
|