通过Express服务器从S3流式传输音频需要太长时间
我想通过向我的Node/Express服务器发出请求,将音频文件从S3传输到我的React客户端。我设法实现了一些可行的方法,但我不确定我是否真的在这里流式传输这个文件,或者直接下载它。我怀疑我可能会下载文件,因为我对服务器的请求需要很长的时间回来:通过Express服务器从S3流式传输音频需要太长时间
Established database connection.
Server listening on port 9000!
::1 - - [18/Apr/2017:21:13:43 +0000] "GET/HTTP/1.1" 200 424 6.933 ms
::1 - - [18/Apr/2017:21:13:43 +0000] "GET /static/js/main.700ba5c4.js HTTP/1.1" 200 217574 1.730 ms
::1 - - [18/Apr/2017:21:13:43 +0000] "GET /index.css HTTP/1.1" 200 - 8.722 ms
Server received a request: GET /tracks
::1 - - [18/Apr/2017:21:13:43 +0000] "GET /tracks HTTP/1.1" 304 - 41.468 ms
Server received a request: GET /tracks/1/stream
::1 - - [18/Apr/2017:21:14:13 +0000] "GET /tracks/1/stream HTTP/1.1" 200 - 636.249 ms
Server received a request: GET /tracks/2/stream
Database query threw an error: ETIMEDOUT
注意636.249毫秒!
你们能否告诉我在这里做错了什么?我粘贴下面我目前的方法的代码;它具有以下功能:
- 客户端发出一个fetch调用到
/tracks/id/stream
- 服务器查询数据库来获取轨道
- Server使用
downloadStream
(从s3 package)来获取文件 - 服务器管道数据到客户端
- 客户端接收数据作为ArrayBuffer
- 客户端解码缓冲区并将其传递到AudioBufferSourceNode
- AudioBufferSourceNode播放音频
服务器端:
app.get('/tracks/:id/stream', (req, res) => {
const id = req.params.id
// Query the database for all tracks
database.query(`SELECT * FROM Tracks WHERE id = ${id}`, (error, results, fields) => {
// Upon failure...
if (error) {
res.sendStatus(500)
}
// Upon success...
const params = {
Bucket: bucketName, // use bucketName defined elsewhere
Key: results[0].key // use the key from the track object
};
// Download stream and pipe to client
const stream = client.downloadStream(params)
stream.pipe(res)
})
});
客户端获取拨打:
const URL = `/tracks/${id}/stream`
const options = { method: 'GET' }
fetch(URL, options)
.then(response => response.arrayBuffer())
.then(data => {
// do some stuff
AudioPlayer.play(data)
})
客户端AudioPlayer,负责处理实际AudioBufferSourceNode :
const AudioPlayer = {
play: function(data) {
// Decode the audio data
context.decodeAudioData(data, buffer => {
// Create a new buffer source
source = context.createBufferSource()
source.buffer = buffer
source.connect(context.destination)
// Start playing immediately
source.start(context.currentTime)
})
},
...
这里有很多错误,所以让我们一个接一个地看看它,不管它是否与你原来的问题有关。
database.query(`SELECT * FROM Tracks WHERE id = ${id}`, (error, results, fields) => {
在这一行中,您将打开自己的SQL注入攻击。 从不在没有正确转义的情况下,将任意数据连接到查询的上下文(或任何其他上下文)。无论您使用的是哪种数据库库,都会有一个您应该使用的参数化方法。
我怀疑我可能会下载文件,因为我对服务器的请求需要很长的时间回来
谁知道......你没有,你向我们展示一个位置我们正在做日志记录,所以很难说日志行是在请求完成之前还是之后。但有一点很清楚,即响应必须至少开始,否则响应状态码将不可知。无论如何,来自S3的第一个资源字节的600毫秒响应时间并不是前所未闻的。
开始=>
- Server使用downloadStream(从S3包)来获取文件
- 服务器管道的数据到客户端
你在浪费与此有很多带宽。您不应该获取文件并将其转发给客户端,您应该做的是用15分钟左右的时间签署临时URL,然后将客户端重定向到该URL。客户将遵循重定向,现在S3负责处理您的客户。它会花费你一半的带宽,更少的CPU资源,并且将从一个更接近你的用户的位置交付。您可以使用AWS JS SDK创建此签名的URL。
开始=>
- 客户机接收到的数据作为ArrayBuffer
有没有流发生在这里。您的客户在播放任何内容之前正在下载整个资源。
你应该做的是创建一个正常的音频实例。它会自动从您的Node.js应用程序重定向到您已签名的S3 URL,并为您处理所有缓冲和流式传输。
let a = new Audio('/tracks/' + encodeURIComponent(id) + '/stream');
a.play();
什么是'client'和'downloadStream()' – peteb
我提到'downloadStream'来自[S3包(https://www.npmjs.com/package/s3);客户也来自那里。 – Gundam194