PDF/图片上传后浏览器空白或乱码,主因是未显式设置contentType;MongoDB默认存为application/octet-stream,需设为application/pdf或image/jpeg等标准值;二进制读取勿用utf8编码;metadata必须用合法对象初始化且字段名禁用.和$;下载时须设Content-Type与Content-Disposition响应头;chunkSizeBytes在机械盘建议设为4MB以避免寻道抖动。

上传时没设 contentType,前端打不开 PDF/图片
文件上传后浏览器点开空白或下载成乱码,大概率是 contentType 没显式指定。MongoDB 默认存为 application/octet-stream,浏览器不识别,也不会触发 PDF 预览或图片渲染。
- PDF 必须传
contentType: 'application/pdf' - JPEG/PNG 要用
'image/jpeg'或'image/png',别写成'jpg'这种非标准值 - Node.js 里用
fs.readFileSync(path)(不带编码参数)读取二进制,再传给uploadFromStream();如果误用fs.readFileSync(path, 'utf8'),PDF 头部 %PDF-1.4 就会被破坏
metadata 初始化错误,导致按业务字段查不到文件
metadata 看似可选,但一旦要用它做查询条件(比如按 userId 找所有附件),就必须用 new Document()(Java)或 plain object(Node.js)初始化——不能传 null、{} 或未声明的 Map 实例。
- Java 中常见错:直接传
Map<String, Object> metadata = new HashMap<>();,但 GridFS 驱动内部会拒绝空 Map,后续find({ "metadata.userId": "u123" })查不到 - 键名禁用点号(
.)和美元符($),否则插入失败且无明确报错,metadata字段在files集合里为空 - Node.js 里传
{ userId: 'u123', originalName: 'report.pdf' }即可,无需额外包装
流没关干净,下载时卡住或返回空内容
调 openDownloadStream() 后直接 pipe 给 HTTP 响应是常规操作,但漏掉关键防护就会出问题:文件存在但响应体为空、连接挂起、内存缓慢泄漏。
- 必须先设响应头:
res.setHeader('Content-Type', file.contentType)和res.setHeader('Content-Disposition', 'inline; filename="xxx"'),否则某些浏览器拒绝渲染 - 别用
toArray()或read()加载整个文件到内存——PDF 或视频一超过几 MB,Node 进程就 OOM - .NET Core 中
GridFSDownloadStream是IDisposable,必须using包裹或显式DisposeAsync();Go 里file.Close()不可省略 - 文件不存在时,
openDownloadStream()返回null(Node.js)或抛异常(C#),不处理会导致 500 错误而非 404
chunkSizeBytes 设太小,机械盘上读取慢得离谱
默认 chunkSizeBytes = 255 * 1024(255KB)在 SSD 上尚可,但在机械硬盘上会引发严重寻道抖动——一个 10MB 文件被切成 40 多个 chunk,驱动反复跳磁头,实测读取延迟翻 3–5 倍。
- 机械盘环境建议设为
4 * 1024 * 1024(4MB),平衡单次 IO 大小与内存压力 - 别盲目设成 8KB 或 64KB:chunk 越多,
chunks集合文档越多,索引膨胀,元数据查询也变慢 - 这个值只影响存储结构,不影响上传逻辑——
uploadFromStream()接口完全兼容,无需改代码
真正卡住读取的,往往不是 MongoDB 本身,而是上传时埋下的隐性缺陷:二进制被当字符串解码、metadata 字段压根没存进去、或者 chunk 分得太碎让硬盘忙不过来。这些问题不会在上传时报错,但会在第一次下载时集体爆发。


















