根本原因是PDF二进制流被误作字符串处理,导致非ASCII字节错误解码;必须用Buffer/Uint8Array原始读取、设置contentType、显式构造GridFSBucket、正确处理下载流与ObjectId类型转换。
GridFS 存 PDF 时为什么文件变大或损坏
根本原因通常是把 PDF 的二进制流误当成字符串处理,比如用
读取后直接传给
—— 这会让非 ASCII 字节被错误解码,PDF 头部(如
)一乱,下游就打不开。
必须用
或
原始二进制方式读取:例如
(不带编码参数)或
上传时指定
,否则默认是
,某些前端库可能不自动触发 PDF 预览
别在上传前对 Buffer 做
、
或任何字符串转换
用 Node.js MongoDB Driver v5+ 上传 PDF 到 GridFS
v5+ 的
默认启用新驱动 API,
不再从
上直接挂载,需显式构造;同时
返回的是 Promise,不是 callback。
初始化 bucket 要传
显式命名,否则默认用
,容易和别的业务冲突
上传流必须是可读流(
)或
,不能是路径字符串
推荐加
字段存业务信息,比如
,后续查起来方便
根据 fileId 查 PDF 并返回给 HTTP 响应
常见错误是调用
后没设响应头,或者用
把整个文件加载进内存——PDF 动辄几 MB,Node.js 进程容易 OOM。
必须用
和
,否则浏览器可能下载而非预览
直接把 download stream
给
,不要
或
注意处理文件不存在:当
返回 null,要手动
用 ObjectId 查询 GridFS 文件元数据但查不到
集合里存的
是
,但如果你用字符串(比如 URL 参数里传的
)直接查,MongoDB 不会自动转类型,结果为空。
查询前必须用
转换,且确保
是合法 24 位十六进制
查元数据用
,不是
—— GridFS 元数据存在
集合,但 driver 封装了这层细节
如果用
,记得
,它的返回值是文档对象,含
、
、
等字段
最容易被忽略的是:GridFS 的
和
集合名默认是
和
,但如果你初始化 bucket 时指定了
,那实际集合就是
和
—— 直接去 shell 里查错地方,永远找不到。
fs.readFileSync(path, 'utf8')gridFSBucket.uploadFromStream()%PDF-1.4BufferUint8Arrayfs.readFileSync(path)fs.createReadStream(path)contentType: 'application/pdf'application/octet-stream.toString()JSON.stringify()MongoClientGridFSBucketdbuploadFromStream(){ bucketName: 'pdfs' }fsfs.createReadStream()Buffermetadata{ originalName: 'report.pdf', userId: 'u123' }const stream = fs.createReadStream('./report.pdf');
const uploadStream = bucket.uploadFromStream(
'report.pdf',
stream,
{
contentType: 'application/pdf',
metadata: { originalName: 'report.pdf', userId: 'u123' }
}
);
const { _id } = await uploadStream;bucket.openDownloadStream()toArray()res.setHeader('Content-Type', 'application/pdf')res.setHeader('Content-Disposition', 'inline; filename="...")piperestoArray()read()bucket.openDownloadStream(fileId)res.status(404).end()const downloadStream = bucket.openDownloadStream(fileId);
if (!downloadStream) {
return res.status(404).end();
}
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'inline; filename="report.pdf"');
downloadStream.pipe(res);files_idObjectId"65a1b2c3d4e5f67890123456"new ObjectId(idString)idStringbucket.find({ _id: objectId })collection.find()pdfs.filesfindOne()awaitlengthuploadDatemetadatafileschunksfs.filesfs.chunksbucketName: 'pdfs'pdfs.filespdfs.chunks