在Node.js项目开发中,图片上传和管理是非常常见的功能需求,结合Multer中间件和MongoDB数据库可以高效实现这一功能。Multer负责处理前端传递的multipart/form-data格式的文件数据,MongoDB则用来存储图片的相关元数据,两者配合可以搭建出稳定可用的图片处理模块。

环境准备与依赖安装
首先我们需要初始化Node.js项目并安装所需的依赖包,核心依赖包括express、multer、mongoose,前者用于搭建服务,后两者分别处理文件上传和数据库操作。
# 初始化项目 npm init -y # 安装依赖 npm install express multer mongoose
MongoDB连接配置
使用mongoose连接MongoDB数据库,同时定义图片信息的Schema,用于存储上传图片的名称、大小、存储路径、上传时间等元数据。
const mongoose = require('mongoose');
// 连接MongoDB,若使用本地数据库可替换为mongodb://127.0.0.1:27017/image_db
mongoose.connect('mongodb://ipipp.com:27017/image_db', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log('MongoDB连接成功');
}).catch((err) => {
console.error('MongoDB连接失败', err);
});
// 定义图片Schema
const imageSchema = new mongoose.Schema({
originalName: String, // 原始文件名
fileName: String, // 存储时的文件名
filePath: String, // 文件存储路径
size: Number, // 文件大小(字节)
uploadTime: { type: Date, default: Date.now } // 上传时间
});
// 创建图片模型
const Image = mongoose.model('Image', imageSchema);
Multer配置与上传逻辑
Multer需要配置存储引擎,我们可以选择磁盘存储,自定义文件存储的名称和路径,同时可以添加文件过滤规则,限制只允许上传图片类型文件。
const multer = require('multer');
const path = require('path');
// 配置存储引擎
const storage = multer.diskStorage({
// 设置文件存储目录
destination: function (req, file, cb) {
cb(null, 'uploads/'); // 文件会存储到项目根目录的uploads文件夹下
},
// 自定义存储的文件名,避免重名
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, uniqueSuffix + path.extname(file.originalname)); // 文件名:时间戳-随机数+原扩展名
}
});
// 文件过滤,只允许上传图片类型
const fileFilter = (req, file, cb) => {
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
if (allowedTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error('只允许上传JPEG、PNG、GIF格式的图片'), false);
}
};
// 初始化multer实例
const upload = multer({
storage: storage,
fileFilter: fileFilter,
limits: {
fileSize: 1024 * 1024 * 5 // 限制文件大小为5MB
}
});
上传接口实现
使用express搭建服务,编写图片上传接口,接口接收到文件后,将文件的元数据存储到MongoDB中,同时返回上传成功的信息。
const express = require('express');
const app = express();
// 创建uploads文件夹,若不存在则自动创建
const fs = require('fs');
if (!fs.existsSync('uploads')) {
fs.mkdirSync('uploads');
}
// 图片上传接口
app.post('/upload', upload.single('image'), async (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ message: '未上传文件' });
}
// 将图片元数据存储到MongoDB
const newImage = new Image({
originalName: req.file.originalname,
fileName: req.file.filename,
filePath: req.file.path,
size: req.file.size
});
await newImage.save();
res.status(200).json({
message: '图片上传成功',
imageInfo: {
id: newImage._id,
originalName: newImage.originalName,
fileName: newImage.fileName,
filePath: newImage.filePath,
size: newImage.size,
uploadTime: newImage.uploadTime
}
});
} catch (err) {
res.status(500).json({ message: '上传失败', error: err.message });
}
});
图片查询与删除功能
除了上传功能,我们还需要实现图片的查询和删除功能,查询可以获取所有已上传的图片列表,删除可以同时删除数据库记录和本地存储的文件。
查询所有图片接口
// 获取所有图片列表
app.get('/images', async (req, res) => {
try {
const images = await Image.find().sort({ uploadTime: -1 }); // 按上传时间倒序排列
res.status(200).json({ message: '查询成功', data: images });
} catch (err) {
res.status(500).json({ message: '查询失败', error: err.message });
}
});
删除图片接口
// 删除指定图片
app.delete('/images/:id', async (req, res) => {
try {
const imageId = req.params.id;
// 先查询图片信息
const image = await Image.findById(imageId);
if (!image) {
return res.status(404).json({ message: '图片不存在' });
}
// 删除本地文件
fs.unlinkSync(image.filePath);
// 删除数据库记录
await Image.findByIdAndDelete(imageId);
res.status(200).json({ message: '删除成功' });
} catch (err) {
res.status(500).json({ message: '删除失败', error: err.message });
}
});
服务启动与测试
最后启动express服务,就可以使用postman或者前端表单测试图片上传功能了。
// 启动服务
const port = 3000;
app.listen(port, () => {
console.log(`服务运行在 http://127.0.0.1:${port}`);
});
测试上传时,前端需要使用enctype="multipart/form-data"的表单,表单中文件字段的name需要和后端upload.single('image')中的参数一致,否则无法正确接收到文件。如果上传过程中出现文件大小超限或者类型不符的错误,Multer会直接返回对应的错误信息,我们可以在接口中添加错误处理逻辑优化返回提示。