如何将对REST调用的响应分成小块?

时间:2016-03-29 23:27:52

标签: node.js html5 video-streaming

我正在使用node.js中的web应用程序。应用程序的某些部分允许用户上载/检索文件。我使用' SoftLayer对象存储' -service来托管这些文件。但是,在投放视频时,它可以在Chrome / Firefox / Android上的HTML5-video元素中正常播放,但在Safari / iOS上却没有。

为了解决这个问题的根源,我在另一个Stackoverflow帖子上遇到了这个解释:

  

iOS设备希望视频以小块的形式到达。例如,流媒体服务器能够做到这一点。但是,blob服务器只是将视频作为blob传递,这不是iOS设备所期望的。有些浏览器足够聪明,可以处理这个,但其他浏览器则没有。

为了检查这个解释是否有意义,我尝试流式传输相同的mp4文件。为了做到这一点,我基于this stackoverflow-post上接受的答案,这实际上适用于所有浏览器和平台,这使我相信我上面引用的解释实际上是正确的。

不幸的是,这个流代码在我的情况下不起作用,因为该文件托管在SoftLayer上,而接受的假定该文件存在于服务器的文件系统上。我与" Softlayer Object Store"通过this API。我现在的代码看起来像这样:

router.get('/testFile', function (req, res) {
  res.writeHead(200, {'Content-Type' : 'video/mp4','Accept-Ranges': 'bytes'});
  request.get({url: authEndpoint, headers: {"X-Auth-Key": apiKey, "X-Auth-User": user}}, function (err, res1) {
    var data = JSON.parse(res1.body);
    var objectPath = data.storage.public + '/' + container + '/' + filename;
    request.get({
      url: objectPath,
      headers: {"X-Auth-Token": res1.headers['x-auth-token']}
    }, function (err) {
      if (err) {
        console.log('error', err);
      }
    }).pipe(res);
  });
});

显然,这段代码没有"流"视频并立即将整个视频发送给客户端。使用此代码,视频无法在Safari中使用。

我想以某种方式按块发送视频块(如上面讨论的stackoverflow-answer中的情况),而不是一次完全发送,但我不知道如何通过REST检索视频时如何执行此操作请求。我注意到API允许在执行GET请求时提供可选的"范围" - 参数但我不确定如何将此用于我的优势。

最后,我还想提一下,我不相信视频的编码就是问题所在。我正在使用此视频http://www.w3schools.com/html/mov_bbb.mp4,当我在iOS / Safari上输入该链接时,它的工作正常。

1 个答案:

答案 0 :(得分:1)

问题在于您尝试pipe来自API的整个响应,包括状态和标题等。

相反,您需要将响应主体转换为可读流并将其传递给响应。要将Buffer转换为ReadableStream,您可以使用stream-buffers

等库

所以,你的代码应该看起来像这样:

router.get('/testFile', function (req, res) {
  res.writeHead(200, {'Content-Type' : 'video/mp4','Accept-Ranges': 'bytes'});
  request.get({url: authEndpoint, headers: {"X-Auth-Key": apiKey, "X-Auth-User": user}}, function (err, res1) {
    var data = JSON.parse(res1.body);
    var objectPath = data.storage.public + '/' + container + '/' + filename;
    request.get({
      url: objectPath,
      headers: {
        "X-Auth-Token": res1.headers['x-auth-token']
      }
    }, function (err, data) {
      if (err) {
        console.log('error', err);
      } else {
        var bodyStream = new streamBuffers.ReadableStreamBuffer({
          frequency: 10,   // in milliseconds. 
          chunkSize: 2048  // in bytes. 
        });
        bodyStream.pipe(res);
        bodyStream.put(data.body);
      }
    });
  });
});