2017-04-18 84 views
0

我想通过向我的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毫秒!

你们能否告诉我在这里做错了什么?我粘贴下面我目前的方法的代码;它具有以下功能:

  1. 客户端发出一个fetch调用到/tracks/id/stream
  2. 服务器查询数据库来获取轨道
  3. Server使用downloadStream(从s3 package)来获取文件
  4. 服务器管道数据到客户端
  5. 客户端接收数据作为ArrayBuffer
  6. 客户端解码缓冲区并将其传递到AudioBufferSourceNode
  7. 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) 
    })  
    }, 
... 
+0

什么是'client'和'downloadStream()' – peteb

+0

我提到'downloadStream'来自[S3包(https://www.npmjs.com/package/s3);客户也来自那里。 – Gundam194

回答

1

这里有很多错误,所以让我们一个接一个地看看它,不管它是否与你原来的问题有关。

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(); 
    
    相关问题