通过Express服务器从S3流式传输音频需要太长时间

时间:2017-04-18 22:31:14

标签: node.js express amazon-s3 fetch audio-streaming

我正在尝试通过向我的Node / Express服务器发出请求,将音频文件从S3传输到我的React客户端。我设法实现了一些有效的方法,但我不确定我是否实际上流式传输文件,或者只是下载它。我怀疑我可能正在下载该文件,因为我对服务器的请求需要很长时间才能回来:

// assuming this file is Container.js
export default withRouter(Container)


// index.js
import Container from './Container'

render(
    <BrowserRouter>
        <Container/>
    </BrowserRouter>,
    document.getElementById('root')
 )

请注意636.249毫秒!

你能告诉我这里做错了吗?我粘贴了下面我当前方法的代码;它执行以下操作:

  1. 客户端对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
  2. 进行抓取调用
  3. 服务器查询数据库以获取跟踪
  4. 服务器使用/tracks/id/stream(来自s3 package)获取文件
  5. 服务器将数据传输到客户端
  6. 客户端以ArrayBuffer
  7. 的形式接收数据
  8. 客户端解码缓冲区并将其传递给AudioBufferSourceNode
  9. AudioBufferSourceNode播放音频
  10. 服务器端:

    downloadStream

    客户端提取呼叫:

    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)
      })
    });
    

    客户端AudioPlayer,负责处理实际的AudioBufferSourceNode:

    const URL = `/tracks/${id}/stream`
    const options = { method: 'GET' }
    
    fetch(URL, options)
    .then(response => response.arrayBuffer())
    .then(data => {
    
      // do some stuff
    
      AudioPlayer.play(data)
    })
    

1 个答案:

答案 0 :(得分:2)

这里有很多错误,所以让我们一块一块地完成它,无论它是否与你原来的问题有关。

  database.query(`SELECT * FROM Tracks WHERE id = ${id}`, (error, results, fields) => {

在这一行中,您将自己打开SQL注入攻击。 从不将任意数据连接到查询(或任何其他上下文)的上下文中,而不进行适当的转义。无论您使用何种数据库,都应该使用参数化方法。

  

我怀疑我可能正在下载该文件,因为我对服务器的请求需要很长时间才能回来

谁知道......您没有向我们展示您正在进行日志记录的单一位置,因此很难说明记录的行是否在请求之前或之后完成。然而,有一点很清楚,响应必须至少开始,否则响应状态代码将不会被知道。无论如何,来自S3的第一个资源字节的600 ms响应时间是闻所未闻的。

  
      
  1. 服务器使用downloadStream(来自s3包)获取文件
  2.   
  3. 服务器将数据传输到客户端
  4.   

你因此浪费了大量的带宽。您应该做的是签署一个15分钟到期的临时URL,然后将客户端重定向到该文件,而不是获取文件并将其中继到客户端。客户端将遵循重定向,现在S3负责处理您的客户。这将花费您一半的带宽,更少的CPU资源,并将从可能更接近您的用户的位置交付。您可以使用AWS JS SDK创建此签名URL。

  
      
  1. 客户端以ArrayBuffer
  2. 的形式接收数据   

这里没有流媒体发生。您的客户正在下载整个资源,然后再播放任何内容。

应该做的是创建一个普通的音频实例。它会自动跟踪您从Node.js应用程序到已签名的S3 URL的重定向,并为您处理所有缓冲和流式传输。

let a = new Audio('/tracks/' + encodeURIComponent(id) + '/stream');
a.play();