MongoDB + ImageKit 集成(后端架构笔记)


目标

允许用户上传图像。
将图像存储在云存储(ImageKit)中。
将返回的图像 URL 保存在 MongoDB 中。
返回正确的响应给客户端。


完整的系统流程

客户端(颤振/邮递员)
→ HTTP 请求(多部分/表单数据)
→ 快速路线
→ Multer 中间件(解析文件)
→ ImageKit 上传服务
→ 云存储
→ 返回的 URL
→ MongoDB(存储 URL)
→ 回复已发回


1. 为什么需要 Multer

Express 默认可以解析 JSON。
但是,图像上传不是 JSON。
它们被发送为:

内容类型:多部分/表单数据

此格式包含原始二进制数据。
仅 Express 无法从此格式提取文件。

穆特解决了这个问题。

穆尔特:

  • 读取传入的请求流
  • 检测文件边界
  • 将文件数据与文本字段分开
  • 将文件附加到 req.file
  • 将文本字段附加到 req.body

多路复用器配置

1
2
3
4
5
6
const multer = require("multer");

const upload = multer({
storage: multer.memoryStorage(),
limits: { fileSize: 5 * 1024 * 1024 }
});

memoryStorage() 表示:
该文件临时存储在 RAM 中,而不是磁盘上。


2. 快速路由实施

1
2
3
4
5
6
7
8
9
10
11
app.post("/create-post", upload.single("image"), async (req, res) => {

const uploadResponse = await uploadFile(req.file.buffer);

await Post.create({
image: uploadResponse.url,
caption: req.body.caption
});

res.status(201).json({ message: "Post Created" });
});

要点:

  • upload.single("image") 在路由处理程序之前运行
  • req.file.buffer 包含原始二进制数据
  • req.body 包含其他表单字段

3.ImageKit服务层

服务层将云逻辑与路由逻辑分开。
这改善了结构和可维护性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const ImageKit = require("imagekit");

const imagekit = new ImageKit({
publicKey: process.env.IMAGEKIT_PUBLIC,
privateKey: process.env.IMAGEKIT_PRIVATE,
urlEndpoint: process.env.IMAGEKIT_URL
});

async function uploadFile(buffer) {
const result = await imagekit.upload({
file: buffer,
fileName: "post_image"
});

return result;
}

module.exports = uploadFile;

为什么要使用服务层?

  • 保持路线清洁
  • 分离业务逻辑
  • 使存储提供商可替换

4.MongoDB 模型结构

1
2
3
4
5
6
7
8
const postSchema = new mongoose.Schema({
image: String,
caption: String,
createdAt: {
type: Date,
default: Date.now
}
});

重要概念:
数据库不存储图像文件。
它只存储从 ImageKit 返回的图像 URL。

为什么?

  • 更好的性能
  • 更好的可扩展性
  • 较小的数据库大小
  • 云存储针对媒体进行了优化

5. 低级内部流程

  1. 客户选择一个图像。
  2. 客户端发送 multipart/form-data 请求。
  3. 服务器接收原始二进制流。
  4. Multer解析流。
  5. 文件被转换为缓冲区。
  6. 缓冲区被发送到ImageKit。
  7. ImageKit将图像上传到云端。
  8. ImageKit 返回一个公共 URL。
  9. URL保存在MongoDB中。
  10. 服务器发送响应。

6. 安全最佳实践

始终执行:

  • 文件大小限制
  • 文件类型验证
  • 凭据的环境变量
  • 正确的错误处理

文件类型验证示例:

1
2
3
4
5
6
7
fileFilter: (req, file, cb) => {
if (file.mimetype.startsWith("image/")) {
cb(null, true);
} else {
cb(new Error("Only image files are allowed"), false);
}
}

7. 架构洞察

后端不永久存储文件。
后端处理文件。
云存储文件。
数据库存储引用(URL)。

该架构具有可扩展性和生产就绪性。


系统组件角色

Multer → 解析多部分数据
ImageKit → 云存储提供商
MongoDB → 存储结构化数据
Express → 处理路由和控制流
服务层 → 处理外部集成


要点

  • 了解多部分/表单数据处理
  • 了解中间件执行顺序
  • 理解关注点分离
  • 存储文件引用,而不是文件
  • 设计后端系统以实现可扩展性

这代表了生产系统中使用的真实媒体上传架构。