基于Moleculer Framework:MongoDB二进制文件下载API开发问题
问题分析与解决方案
现有代码的核心问题
- 创建
WriteStream后未执行写入操作,也未处理流的结束事件,导致文件无法保存 fs.write用法错误,正确方式应为fs.writeFile或通过流写入Buffer.from(result.file.buffer, result.file.mimetype)逻辑错误:第二个参数应为编码格式(如base64)而非MIME类型,且result.file.buffer本身已是Buffer,无需二次转换- 未向客户端返回响应,前端无法触发下载
- MongoDB连接关闭时机不合理,应确保操作完成后再关闭
解决方案
1. 实现客户端直接下载(API核心需求)
修改handler函数,通过设置响应头触发浏览器下载,同时确保数据库连接安全关闭:
async handler(ctx, res) { console.log("Came to main action handler-- DOWNLOAD"); const fileId = ctx.params.id; console.log("Download step 1: " + fileId); let client; try { client = await MongoClient.connect(mongoURL); const db = client.db(dbName); const collection = db.collection(collectionName); const result = await collection.findOne({ _id: new ObjectId(fileId) }); if (!result) { ctx.status = 404; ctx.body = "文件不存在"; return; } const fileBuffer = result.file.buffer; const fileName = result.file.originalname; const mimeType = result.file.mimetype; // 设置响应头,强制浏览器触发下载 ctx.set('Content-Type', mimeType); ctx.set('Content-Disposition', `attachment; filename="${encodeURIComponent(fileName)}"`); ctx.set('Content-Length', fileBuffer.length); // 将二进制数据返回给客户端 ctx.body = fileBuffer; console.log(`文件 ${fileName} 已触发下载`); } catch (error) { console.log("错误: " + error); ctx.status = 500; ctx.body = "服务器内部错误"; } finally { // 确保数据库连接无论结果如何都会关闭 if (client) { await client.close(); } } },
2. 同时保存文件到服务器本地(可选需求)
如果需要将文件保存到服务器本地,修正流写入逻辑:
// 在获取到fileBuffer和fileName后添加以下代码 const savePath = `C:/upload/${fileName}`; const writeStream = fs.createWriteStream(savePath); // 写入Buffer并结束流 writeStream.write(fileBuffer); writeStream.end(); // 监听流事件处理结果 writeStream.on('finish', () => { console.log(`文件已保存至 ${savePath}`); }); writeStream.on('error', (err) => { console.error("保存文件失败:", err); });
关键说明
- 直接使用
result.file.buffer即可,无需额外转换 encodeURIComponent用于处理文件名中的特殊字符,避免下载时出现乱码finally块确保MongoDB连接资源被正确释放- 流操作需监听
finish和error事件,处理保存成功或失败的情况
内容的提问来源于stack exchange,提问作者Lalith Rajendran
相关产品推荐
相关产品推荐

