今天在做小程序作业时,因为后端用的node
,在写一个下载文件的接口时,我是这样写的:
router.get("/bookFile", (req, res, next) => {
const url = `books/${decodeURI(req.query.filename)}`
const exist = fs.existsSync(url)
if (exist) {
res.set({
"Content-type": "application/octet-stream",
"Content-Disposition": "attachment;filename=" + encodeURI(req.query.filename)
});
fReadStream = fs.createReadStream(url);
fReadStream.on("data", (chunk) => {
res.write(chunk)
});
fReadStream.on("end", function () {
res.end();
});
} else {
res.set("Content-type", "text/html");
res.send("file not exist!");
res.end();
}
})
然后在微信小程序这边调用wx.downloadFile
接口返回一个downloadTask
,再去调用wx.onProgressUpdate
想去获取下载进度时,发现res.progress
为null,我就奇了怪了,之前用别人的链接还可以获取啊,怎么自己写的接口就获取不到这个progress
了,然后我去看了看响应报文:
再对比了一下别人的能正常获取到progress
值的下载链接的响应报文:
发现比我自己写的多了一个关键的响应头:Content-Length
,加上之后确实能正常获取到progress
值了。
在摸索这个问题时,我看到了这篇文章 nodejs Stream 使用中的陷阱 ,发现我以上的写法还有一个问题,就是有可能在下载一些较大的文件时,可能会出现内存泄露的问题,对于以上的两个问题,我将原来的接口代码做了以下的优化:
router.get("/bookFile", (req, res, next) => {
const url = `books/${decodeURI(req.query.filename)}`
const stat = fs.statSync(url);
const exist = fs.existsSync(url)
if (exist) {
res.set({
"Content-type": "application/octet-stream",
"Content-Disposition": "attachment;filename=" + encodeURI(req.query.filename),
"Content-Length": stat.size
});
fReadStream = fs.createReadStream(url);
fReadStream.on("data", (chunk) => {
if (!res.write(chunk)) { //判断写缓冲区是否写满(node的官方文档有对write方法返回值的说明)
fReadStream.pause(); //如果写缓冲区不可用,暂停读取数据
}
});
fReadStream.on("end", function () {
res.end();
});
res.on("drain", function () { //写缓冲区可用,会触发"drain"事件
fReadStream.resume(); //重新启动读取数据
});
} else {
res.set("Content-type", "text/html");
res.send("file not exist!");
res.end();
}
})