【发布时间】:2022-01-25 22:04:11
【问题描述】:
我有一个 Express 服务器,它接收带有附加 FLAC 音频文件的 FormData。该代码对几个不同大小(10 - 70MB)的文件按预期工作,但其中一些文件卡在'file' 事件中,我无法弄清楚为什么会发生这种情况。更奇怪的是,以前没有触发file.on('close', => {}) 事件的文件(如Busboy 的文档中所示)突然触发,并且文件已成功上传。
对我来说,这似乎完全是随机的,因为我已经尝试了十几个不同大小和内容类型(音频/flac 和音频/x-flac)的文件,但结果不一致。然而,有些文件根本不起作用,即使我尝试多次解析它们。然而,如果有足够的尝试,某些文件可以被解析和上传?
在'file' 事件中是否有一些我未能处理的错误?我确实尝试收听file.on('error', => {}) 事件,但没有发现任何错误。 Other answers 建议必须使用 file 流以使 'close' 事件继续进行,但我认为 file.pipe(fs.createWriteStream(fileObject.filePath)); 会这样做,对吗?
如果我忘记在我的问题中包含一些重要信息,请告诉我。这已经困扰我大约一周了,所以我很乐意提供任何相关的信息来帮助我克服这个障碍。
app.post('/upload', (request, response) => {
response.set('Access-Control-Allow-Origin', '*');
const bb = busboy({ headers: request.headers });
const fields = {};
const fileObject = {};
bb.on('file', (_name, file, info) => {
const { filename, mimeType } = info;
fileObject['mimeType'] = mimeType;
fileObject['filePath'] = path.join(os.tmpdir(), filename);
file.pipe(fs.createWriteStream(fileObject.filePath));
file.on('close', () => {
console.log('Finished parsing of file');
});
});
bb.on('field', (name, value) => {
fields[name] = value;
});
bb.on('close', () => {
bucket.upload(
fileObject.filePath,
{
uploadType: 'resumable',
metadata: {
metadata: {
contentType: fileObject.mimeType,
firebaseStorageDownloadToken: fields.id
}
}
},
(error, uploadedFile) => {
if (error) {
console.log(error);
} else {
db.collection('tracks')
.doc(fields.id)
.set({
identifier: fields.id,
artist: fields.artist,
title: fields.title,
imageUrl: fields.imageUrl,
fileUrl: `https://firebasestorage.googleapis.com/v0/b/${bucket.name}/o/${uploadedFile.name}?alt=media&token=${fields.id}`
});
response.send(`File uploaded: ${fields.id}`);
}
}
);
});
request.pipe(bb);
});
更新:1
我决定用file.on('data', (data) => {}) 测量每次上传时传输的字节数,只是为了看看问题是否总是相同的,结果证明这也是完全随机的。
let bytes = 0;
file.on('data', (data) => {
bytes += data.length;
console.log(`Loaded ${(bytes / 1000000).toFixed(2)}MB`);
});
第一个测试用例:Fenomenon - 巴克斯顿昏昏欲睡的草地
来源:https://fenomenon.bandcamp.com/track/sleepy-meadows-of-buxton
- 大小:30.3MB
- 编解码器:FLAC
- MIME:音频/flac
三次尝试的结果:
- 加载了 18.74MB,然后卡住了
- 加载了 5.05MB,然后卡住了
- 加载了 21.23MB,然后卡住了
第二个测试用例:Almunia - New Moon
来源:https://almunia.bandcamp.com/track/new-moon
- 大小:38.7MB
- 编解码器:FLAC
- MIME:音频/flac
三次尝试的结果:
- 加载了 12.78MB,然后卡住了
- 已加载38.65,已成功上传!
- 已加载38.65,已成功上传!
正如您所见,这种行为至少可以说是不可预测的。此外,这两个成功的上传确实从 Firebase 存储无缝播放,所以它确实按预期工作。我无法理解的是为什么它并不总是有效,或者至少在大多数情况下,排除任何与网络相关的故障。
更新:2
我绝望地试图理解这个问题,所以我现在创建了一个与我的实际项目非常相似的场景,并将代码上传到GitHub。它非常小,但我确实添加了一些额外的库以使前端使用起来愉快。
除了一个用于后端的 Express 服务器和一个用于前端的简单 Vue 应用程序之外,它并没有太多的东西。在 files 文件夹中,有两个 FLAC 文件;其中一个只有 4.42MB,以证明代码有时确实有效。另一个文件要大得多,为 38.1MB,以可靠地说明问题。随意尝试任何其他文件。
请注意,必须修改前端以允许 FLAC 文件以外的文件。我选择只接受 FLAC 文件,因为这是我在实际项目中使用的。
【问题讨论】:
-
我在启用这些选项的情况下运行了一些测试,但不幸的是这并没有什么不同:
file.pipe(fs.createWriteStream(fileObject.filePath, { autoClose: true, emitClose: true }));。createWriteStream()不会自动触发'close'事件吗? -
我明白你在说什么,但流有时会自动关闭,所以它应该可以工作。我已经用一些示例更新了我的原始问题,这些示例说明了我的实现是多么不可预测。
-
相关? github.com/mscdex/busboy/issues/264 - tl:dr 正在监听从
createWriteStream()返回的 writeStream 上的finish事件之前你调用bucket.upload()。为什么?在您尝试使用结果之前,并非所有数据都已从缓冲区中刷新。 -
这是有道理的。我现在等待
createWriteStream()发出'finish'事件。问题似乎是不保证会发生此事件,这可能是问题的根源。有时,没有事件,也没有任何错误。我的代码:file.pipe(fs.createWriteStream(fileObject.filePath)).on('finish', () => {});. -
所以接下来的想法是
.pipe()readable是end()的信号,因此在可写完成之前关闭writable?您可以通过添加{end: false}作为调用.pipe()的第二个参数来测试这一点。请注意,当readable中出现错误情况时,不会关闭可写对象的情况@
标签: javascript express busboy