MongoDB与GridFS文件下载问题:可本地下载但浏览器无法触发
问题原因
你现在的代码是把MongoDB里的文件写到服务器本地文件系统,而不是把文件内容返回给浏览器请求。而且你直接调用res.end(),浏览器接收到的是空响应,自然触发不了下载。
修复方案
要让浏览器触发下载,需要把GridFS的文件流直接pipe到响应对象res,同时设置正确的HTTP响应头告诉浏览器这是一个需要下载的文件。
具体修改步骤
- 删掉
fs.createWriteStream相关代码,把openDownloadStreamByName返回的流直接pipe到res - 设置
Content-Disposition头,指定下载后的文件名,比如attachment; filename="your-file.svg" - 可选:设置
Content-Type头匹配文件类型,比如SVG文件用image/svg+xml,如果不确定类型可以用通用的application/octet-stream - 处理文件不存在等错误情况,避免请求挂起
修改后的代码示例
const conn = mongoose.createConnection(process.env.URL, { useNewUrlParser: true, useUnifiedTopology: true }) const bucket = new GridFSBucket(conn, {bucketName: 'uploads'}); router.get('/download', (req, res) => { const fileName = '3987a162969935378c4f8cbe5d95bb46.svg'; // 打开GridFS下载流 const downloadStream = bucket.openDownloadStreamByName(fileName); // 设置响应头,触发浏览器下载 res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`); res.setHeader('Content-Type', 'image/svg+xml'); // 把文件流pipe到响应对象 downloadStream.pipe(res); // 处理流错误 downloadStream.on('error', (err) => { res.status(404).send('文件不存在'); }); // 流结束时自动完成响应 downloadStream.on('end', () => { res.end(); }); })
关键点说明
Content-Disposition: attachment是告诉浏览器这是一个附件,需要触发下载而不是直接预览- 直接pipe到
res会自动把文件内容发送给浏览器,不需要手动调用res.end()(流结束时会自动完成,但可以在end事件里确保响应结束) - 一定要处理错误,比如文件不存在时,GridFS流会触发error事件,此时要返回404等错误响应,避免请求一直挂着
内容的提问来源于stack exchange,提问作者Luis A
相关产品推荐
相关产品推荐

