node.js - 试图检索存储在 AWS S3 中的 mp3 文件并将其作为 Blob 加载到我的 React 客户端中......它不起作用
问题描述
我有一个反应网络应用程序,允许用户在浏览器中录制 mp3 文件。这些 mp3 文件保存在 AWS S3 存储桶中,可以在用户的下一个会话期间检索并加载回 React 应用程序。
保存文件工作得很好,但是当我尝试使用 getObject() 检索文件并尝试在客户端创建一个 mp3 blob 时,我得到一个小的、不可用的 blob:
这是录制的 mp3 文件的旅程:
1) 保存到 S3
在我的 Express/Node 服务器中,我收到上传的 mp3 文件并保存到 S3 存储桶:
//SAVE THE COMPLETED AUDIO TO S3
router.post("/", [auth, upload.array('audio', 12)], async (req, res) => {
try {
//get file
const audioFile = req.files[0];
//create object key
const userId = req.user;
const projectId = req.cookies.currentProject;
const { sectionId } = req.body;
const key = `${userId}/${projectId}/${sectionId}.mp3`;
const fileStream = fs.createReadStream(audioFile.path)
const uploadParams = {
Bucket: bucketName,
Body: fileStream,
Key: key,
ContentType: "audio/mp3"
}
const result = await s3.upload(uploadParams).promise();
res.send(result.key);
} catch (error) {
console.error(error);
res.status(500).send();
}
});
据我所知,现阶段没有问题。该文件以“type:mp3”和“Content-Type:audio/mp3”在我的 S3 存储桶中结束。
2) 从 S3 存储桶加载文件
当加载反应应用程序时,在我的 Express/Node 服务器中发出 HTTP GET 请求以从 S3 存储桶中检索 mp3 文件
//LOAD A FILE FROM S3
router.get("/:sectionId", auth, async(req, res) => {
try {
//create key from user/project/section IDs
const sectionId = req.params.sectionId;
const userId = req.user;
const projectId = req.cookies.currentProject;
const key = `${userId}/${projectId}/${sectionId}.mp3`;
const downloadParams = {
Key: key,
Bucket: bucketName
}
s3.getObject(downloadParams, function (error, data) {
if (error) {
console.error(error);
res.status(500).send();
}
res.send(data);
});
} catch (error) {
console.error(error);
res.status(500).send();
}
});
3) 在客户端创建一个 Blob URL
最后,在 React 客户端中,我尝试从返回的数组缓冲区创建一个“音频/mp3”blob
const loadAudio = async () => {
const res = await api.loadAudio(activeSection.sectionId);
const blob = new Blob([res.data.Body], {type: 'audio/mp3' });
const url = URL.createObjectURL(blob);
globalDispatch({ type: "setFullAudioURL", payload: url });
}
创建的 blob 尺寸严重不足,似乎完全无法使用。下载文件会导致“失败 - 无文件”错误。
我已经坚持了几天了,没有运气。我将非常感谢您提供的任何建议!
谢谢
编辑 1
这里只是一些附加信息:在上传参数中,我将 Content-Type 明确设置为 audio/mp3。这是因为未设置时,Content-Type 默认为“application/octet-stream”。无论哪种方式,我都会遇到相同结果的相同问题。
编辑 2 应评论者的要求,这是调用完成后客户端可用的 res.data:
解决方案
根据客户端上的输出res.data
,您需要做几件事:
res.data.Body
用with替换使用res.data.Body.data
(因为实际的数据数组在 的data
属性中res.data.Body
)- 将 a 传递
Uint8Array
给Blob
构造函数,因为现有数组的类型较大,这将创建无效的 blob
把它们放在一起,你最终会替换:
const blob = new Blob([res.data.Body], {type: 'audio/mp3' });
和:
const blob = new Blob([new Uint8Array(res.data.Body.data)], {type: 'audio/mp3' });
说了这么多,根本问题是 NodeJS 服务器正在将内容作为来自 S3 的响应的 JSON 编码序列化发送,这对于您正在做的事情可能是矫枉过正的。相反,您可以Buffer
直接发送交叉,这将涉及在服务器端替换:
res.send(data);
和:
res.set('Content-Type', 'audio/mp3');
res.send(data.Body);
并在客户端(可能在loadAudio
方法中)将响应处理为 blob 而不是 JSON。如果使用Fetch API,那么它可能很简单:
const blob = await fetch(<URL>).then(x => x.blob());
推荐阅读
- c++ - C++ 神经网络实现 XOR.Output 总是接近 0.5
- javascript - Javascript/React Native 循环仅将变量更新为最后一个值
- traefik - 路径的 Traefik basicauth
- c# - VS2015:Microsoft.CSharp.Core.targets(67,5):错误MSB6004:指定的任务可执行位置“...\csc”无效
- php - Laravel - 运行播种机时在 Guzzle 函数中抛出异常
- javascript - var module = require() 还是 const {module} = require()?
- python - 将 for 循环转换为 numpy 数组
- sql - 为什么在导入 CSV 时在 postgresql 中出现“整数类型的输入语法无效”?
- python - 如何在 Pygame 中播放随机 Mp3 文件
- gradle - Gradle - 从测试模块运行应用程序