前端分片上传需经后端中转,不可直传GridFS;应按5MB切片,携带fileId、chunkIndex等元数据POST至自定义接口,由后端用GridFSBucket.openUploadStreamWithId写入。

前端分片上传时如何构造合法的 GridFS 文件流
GridFS 本身不接受前端直传,必须经后端中转。所谓“直传”其实是前端分片、后端拼接写入 GridFS —— 这点常被误解,导致前端强行往 /fs/chunks 发请求,结果返回 405 Method Not Allowed 或 401 Unauthorized。
真正可行的路径是:前端按固定大小切片(如 5MB),每片携带 fileId、chunkIndex、totalChunks 等元数据,POST 到你自己的上传接口(比如 /api/upload/chunk),由后端用 GridFSBucket 的 openUploadStreamWithId 和 write 组装。
- 切片大小建议设为
5 * 1024 * 1024,避开 Node.js 默认stream的 highWaterMark 限制 - 务必在首片上传前生成唯一
fileId(推荐new ObjectId()),所有分片共用同一个,否则后端无法合并 - 不要依赖前端计算
md5或sha256校验 —— 浏览器 Blob.slice() 在某些安卓 WebView 下会改变二进制内容,校验必然失败
为什么不能跳过后端直接 PUT 到 MongoDB 的 fs.chunks
MongoDB 不暴露 fs.chunks 集合作为 HTTP 接口,驱动层也禁止客户端直写 chunk 文档:缺少 _id 生成逻辑、files_id 关联校验、n 序号连续性保障,且 BSON 文档结构(如 data 字段必须是 BinData 类型)前端无法安全构造。
常见错误现象:insert document must contain an _id field、files_id is missing、或插入后 mongofiles list 看不到文件 —— 全是因为绕过 GridFSBucket 抽象,手动插数据违反了内部约束。
立即学习“前端免费学习笔记(深入)”;
- 所有对
fs.files和fs.chunks的写操作,必须通过官方驱动的GridFSBucket实例完成 -
GridFSBucket.openUploadStreamWithId是唯一支持分片续传的入口,它会自动处理 chunk 分片、序号分配和文件文档创建 - 如果用
insertOne往fs.chunks塞数据,MongoDB 不报错但find查不到对应文件 —— 因为fs.files没同步更新
前端分片逻辑里最容易漏掉的三个状态管理点
分片上传不是发完请求就完事,前端必须自己维护上传进度、失败重试、断点续传上下文,MongoDB 本身不保存这些状态。
- 每个分片响应必须返回服务端记录的
chunkIndex,前端据此判断是否已上传成功,避免重复提交 - 网络中断后,需先 GET
/api/upload/status?fileId=xxx获取已上传的chunkIndex数组,再从下一个索引继续 - 最后一片上传成功后,必须显式调用
/api/upload/complete?fileId=xxx,让后端调用bucket.close()并写入fs.files—— 否则文件永远“未完成”,findOne查不到
Node.js 后端接收分片时的 Buffer 处理陷阱
Express 默认不会把 multipart body 解析成原始 Buffer,而 GridFSBucket.write 要求输入是 Buffer 或 Uint8Array。常见错误是直接传 req.file.buffer(multer 解析后可能被转成 base64 字符串)或 req.body.data(JSON 解析后丢失二进制精度)。
- 用
multer.memoryStorage()+limits: { fileSize: Infinity },确保req.file.buffer是原生Buffer - 禁用
encoding相关中间件(如body-parser的urlencoded),它们会污染req.rawBody - 验证
req.file.buffer instanceof Buffer,不是则立刻return res.status(400).send('invalid chunk data')
MongoDB 的 GridFS 设计初衷就是服务端流式写入,前端能做的只有分片、调度、重试和元数据组装。任何试图“绕过服务端直连 GridFS”的方案,最终都会卡在 BSON 类型、事务一致性或驱动 API 限制上。

















