在 Node.js 开发中,文件上传是一个常见的需求。而 multer
是一个非常强大且易用的中间件,专门用于处理 multipart/form-data
类型的表单数据,尤其是文件上传。
一、Multer 的安装
使用 npm
可以轻松安装 multer
:
npm install multer
二、Multer 的功能
- 文件上传处理:
- 能够自动解析客户端发送的包含文件上传的
multipart/form-data
请求,将文件数据和其他表单字段分离出来。 - 提供多种存储方式,可以将上传的文件存储在本地文件系统、内存或云存储等位置。
- 允许自定义上传文件的命名规则和存储路径,方便管理和组织上传的文件。
- 文件过滤:
- 可以基于文件类型过滤,只接受特定类型的文件上传,例如只允许上传图片文件或文档文件。通过检查文件的 MIME 类型或文件扩展名来进行过滤。
- 可以基于文件大小过滤,设置上传文件的大小限制,防止用户上传过大的文件导致服务器资源耗尽。
- 错误处理:
- 能够检测文件上传过程中可能出现的各种错误,如文件类型不匹配、文件大小超过限制、上传过程中出现网络问题等。
- 允许开发者自定义错误响应,向客户端返回特定的错误消息和状态码。
- 多文件上传支持:
- 支持同时处理多个文件的上传,用户可以在一个表单中选择多个文件进行上传。
- 可以处理表单中以数组形式出现的文件字段。
三、Multer 的用法
3.1Multer 启动
1.创建存储配置:
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
// 指定文件存储的目标目录
cb(null, './uploads');
},
filename: function (req, file, cb) {
// 自定义文件名
cb(null, Date.now() + '-' + file.originalname);
},
});
这里创建了一个存储配置对象,指定了文件存储的目标目录和文件名的生成规则。
2.创建 multer
实例:
const upload = multer({ storage });
使用存储配置创建一个 multer
实例。
3.在路由中使用:
const express = require('express');
const app = express();
app.post('/upload', upload.single('file'), (req, res) => {
// 处理上传后的文件
res.send('File uploaded successfully!');
});
在路由中使用 upload.single('file')
中间件来处理单个文件上传。这里 'file'
是表单中文件字段的名称。
3.2Multer 功能
1.文件上传处理:
- 创建存储配置,指定文件存储在本地文件系统的目标目录和文件名生成规则。
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
// 指定文件存储的目标目录为 './uploads'
cb(null, './uploads');
},
filename: function (req, file, cb) {
// 以当前时间戳和原始文件名组合生成文件名
cb(null, Date.now() + '-' + file.originalname);
},
});
const upload = multer({ storage });
- 在路由中使用中间件处理单个文件上传。
const express = require('express');
const app = express();
app.post('/uploadSingle', upload.single('file'), (req, res) => {
res.send('Single file uploaded successfully!');
});
当客户端向 /uploadSingle
路由发送包含单个文件的请求时,multer
会将文件存储在指定的目录中,并根据配置生成文件名。
2.文件过滤:
- 基于文件类型过滤,只接受特定的 MIME 类型文件。
const fileFilter = function (req, file, cb) {
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(new Error('Only JPEG and PNG images are allowed.'), false);
}
};
const storageWithFilter = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads');
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname);
},
});
const uploadWithFilter = multer({ storage: storageWithFilter, fileFilter });
app.post('/uploadFiltered', uploadWithFilter.single('file'), (req, res) => {
res.send('Filtered file uploaded successfully!');
});
在这个例子中,只有 JPEG 和 PNG 类型的图片文件会被接受,其他类型的文件会触发错误。
- 基于文件大小过滤,设置最大文件大小为 5MB。
const maxSize = 5 * 1024 * 1024; // 5MB
const fileFilterBySize = function (req, file, cb) {
if (file.size <= maxSize) {
cb(null, true);
} else {
cb(new Error('File size exceeds the limit.'), false);
}
};
const storageWithSizeFilter = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads');
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname);
},
});
const uploadWithSizeFilter = multer({
storage: storageWithSizeFilter,
fileFilter: fileFilterBySize,
});
app.post('/uploadSizeFiltered', uploadWithSizeFilter.single('file'), (req, res) => {
res.send('Size-filtered file uploaded successfully!');
});
如果上传的文件大小超过 5MB,会触发错误响应。
3.错误处理:
- 捕获文件上传过程中的错误,并返回自定义的错误响应。
app.post('/uploadWithErrorHandling', uploadWithSizeFilter.single('file'), (req, res, next) => {
if (req.file && req.file.error) {
// 如果有文件上传错误,返回错误响应
res.status(400).send({ error: req.file.error.message });
} else {
res.send('File uploaded successfully or no file was uploaded.');
}
});
在这个例子中,如果文件上传过程中出现错误,会检查 req.file.error
是否存在,如果存在,则返回包含错误消息的 400 错误响应。
4.多文件上传支持:
- 处理多个文件上传,以数组形式存储。
const multipleUpload = multer({ storage: storageWithFilter }).array('files', 5); // 最多接受 5 个文件
app.post('/uploadMultiple', multipleUpload, (req, res) => {
res.send('Multiple files uploaded successfully!');
});
客户端可以在表单中使用多个文件字段,名称为 files
,最多上传 5 个文件。
- 处理多个文件上传,每个文件有不同的字段名。
const fieldsUpload = multer({ storage: storageWithFilter }).fields([
{ name: 'image1', maxCount: 1 },
{ name: 'image2', maxCount: 1 },
]);
app.post('/uploadFields', fieldsUpload, (req, res) => {
res.send('Files with different field names uploaded successfully!');
});
这个例子中,客户端可以上传两个文件,分别使用 image1
和 image2
作为字段名,每个字段最多上传一个文件。
5.处理小文件且需要快速响应
- 当处理一些非常小的文件(例如图标、小尺寸的图片等)时,将文件存储在内存中可以避免磁盘 I/O 操作,从而加快处理速度。
- 例如,在一个实时性要求较高的应用中,用户上传一个小的头像图片,希望能够尽快看到更新后的头像。使用内存存储可以快速处理这个小文件,然后立即返回响应给用户,而不需要等待磁盘写入操作完成。
const multer = require('multer');
const express = require('express');
const storage = multer.memoryStorage();
const upload = multer({ storage });
const app = express();
app.post('/upload', upload.single('file'), (req, res) => {
// 在这里可以对存储在内存中的文件进行快速处理
res.send('File uploaded and processed in memory!');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
四、Multer 的 API 详解
multer.diskStorage(options)
:
destination
:回调函数,用于指定文件存储的目标目录。接收req
(请求对象)、file
(正在处理的文件对象)和cb
(回调函数)作为参数。filename
:回调函数,用于指定上传文件的文件名。同样接收req
、file
和cb
作为参数。
multer.memoryStorage()
:将文件存储在内存中,适用于小文件或需要快速处理的情况。multer({ storage })
:使用存储配置创建一个multer
实例。upload.single(fieldname)
:处理单个文件上传。fieldname
是表单中文件字段的名称。upload.array(fieldname, maxCount)
:处理多个文件上传,以数组形式存储。fieldname
是表单中文件字段的名称,maxCount
是可选的最大文件数量限制。upload.fields(fields)
:处理多个文件上传,每个文件有不同的字段名。fields
是一个对象数组,每个对象包含name
(字段名)和maxCount
(可选的最大文件数量限制)。
总之,multer
中间件为 Node.js 中的文件上传提供了强大而灵活的解决方案,通过简单的配置和 API 调用,可以轻松实现文件上传功能,并满足各种不同的需求。