我想从我的MongoDB数据库下载文件。我发现使用GridFS存储桶的openDownloadStream可以将其通过管道传输到Node的fs createWriteStream,然后在其“完成”时将该数据发送到客户端以使用res下载进行下载。我的问题是几次尝试下载文件后,超时安全缓冲失败,客户端无法及时找到文件,浏览器随后给出了空响应错误。但是,几秒钟后,文件最终会下载。
我正在将mongoDB集成到已经具有下载功能的现有服务器中。以前,文件存储在项目的文件系统中,而现在位于MongoDB中。我已经尝试过运往其他地方,但没有运气。
// Router's Download Logic
router.get("/download", function(req, res) {
setTimeout(download, 2000);
function download() {
var bucket = new mongodb.GridFSBucket(localDatabase())
bucket.openDownloadStreamByName(file)
.pipe(fs.createWriteStream(file))
.on('error', function(error) {
assert.ifError(error)
})
.on('finish', function() {
console.log(`Downloaded ${file}`)
res.download(file)
fs.access(file, function(err) {
if (err) {
console.log(err)
}
else {
fs.unlinkSync(file)
}
})
})
}
});
我希望该文件在2秒的窗口后下载,从而使函数有足够的时间运行。下载大约3次后,我得到的是一个空响应错误。我最终获得了该文件,但似乎我在一台服务器实例中下载的文件越多,下载->管道-> createWriteStream所花费的时间就越长。
编辑:问题来自取消链接。我更改了转到TEMP文件夹的路径,但我不想永远将这些文件存储在其中。我也不想像下载它们一样使用相同的算法取消链接,因为这就是问题所在。关于此的任何建议确实会有所帮助。
如编辑中所述,问题实际上是在与res.download同时调用取消链接的情况,这导致了挂断。为了避免这个小窗口,我在删除文件功能中添加了setTimeout。一个可能的错误是当您下载两个文件的速度太快时,为避免这种情况,我发出了警报,让用户知道在等待下载完成之后才尝试再次下载。
router.get("/download", function(req, res) {
setTimeout(download, 1000);
function download(callback) {
var bucket = new mongodb.GridFSBucket(localDatabase())
bucket.openDownloadStreamByName(file)
.pipe(fs.createWriteStream('private/TEMP/' + file))
.on('error', function(error) {
assert.ifError(err)
})
.on('finish', function() {
res.download('private/TEMP/' + file)
console.log(`Downloaded ${file}`)
setTimeout(removeFile, 1200)
})
}
function removeFile() {
fs.access('private/TEMP/' + file, function(err) {
if (err) {
console.log(err)
}
else {
fs.unlinkSync('private/TEMP/' + file)
}
})
}
});