如何将对 REST 调用的响应分成小块?
Posted
技术标签:
【中文标题】如何将对 REST 调用的响应分成小块?【英文标题】:How to chop up response to REST-call into small chunks? 【发布时间】:2016-07-17 18:06:27 【问题描述】:我正在使用 node.js 开发一个 Web 应用程序。应用程序的某些部分允许用户上传/检索文件。我使用“SoftLayer 对象存储”服务来托管这些文件。但是,在提供视频时,它在 Chrome/Firefox/android 上的 html5-video 元素中可以正常播放,但在 Safari/ios 上却不行。
为了深入了解这个问题,我在另一个 ***-post 上遇到了这个解释:
iOS 设备希望视频以小块形式出现。因此,例如流媒体服务器能够做到这一点。但是,blob 服务器只是将视频作为 blob 处理,这不是 iOS 设备所期望的。有些浏览器足够聪明,可以处理这个问题,但有些则不然。
为了检查这个解释是否有意义,我尝试流式传输相同的 mp4 文件。为了做到这一点,我基于this ***-post 上接受的答案,这实际上在所有浏览器和平台上都运行良好,这让我相信我上面引用的解释实际上是正确的。
不幸的是,这个流代码在我的情况下不起作用,因为该文件托管在 SoftLayer 上,而接受假设该文件存在于服务器的文件系统上。我通过this API 与“Softlayer Object Store”进行通信。我现在的代码如下所示:
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 中播放。
我想以某种方式逐块发送视频(就像上面讨论的 ***-answer 中的情况一样),而不是一次全部发送,但我不知道当通过 REST 检索视频时如何执行此操作-要求。我确实注意到 API 允许在执行 GET 请求时提供可选的“范围”参数,但我不确定如何利用它来发挥自己的优势。
最后我还想提一下,我不认为视频的编码是问题所在。我正在使用这个视频http://www.w3schools.com/html/mov_bbb.mp4,当我在 iOS/safari 上输入该链接时,它工作得很好。
【问题讨论】:
【参考方案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);
);
);
);
【讨论】:
感谢您的评论。我相信你让我走上了正确的轨道,但我希望你能给我更多的指导,因为流缓冲区的文档非常少。我现在的代码看起来像这样 (pastebin.com/X7LNj7Qa) 但它不起作用。我不确定我是否以正确的方式将数据放在 ReadableStreamBuffer 上(第 23 行),是否以正确的方式设置标题(第 12 行)以及是否以正确的方式管道传输缓冲区(第 27 行)。 我正在通过一个网页进行测试,该网页包含一个以“/testFile”端点为源的 HTML5 视频元素。 “写入数据”被多次写入控制台(因为第 26 行),所以我很确定我将数据放在 bodyStream 上。然而,视频根本没有播放,node.js 给出了以下警告:检测到可能的 EventEmitter 内存泄漏。增加了 11 位听众。使用emitter.setMaxListeners() 增加限制。 @Simon nonono,您不需要添加“数据”侦听器。只需将 bodyStream 管道传输到 res 并放置数据。我已经编辑了答案,现在应该有正确的代码 @Petr 其他人指出选项“encoding:null”也应该包含在请求调用中。添加后,电影在 chrome 和 firefox 中运行。它在 safari 中仍然不起作用,但这超出了这个问题的范围。感谢您的帮助!以上是关于如何将对 REST 调用的响应分成小块?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 REST API 获取响应并从 jquery ajax 调用执行操作?
如果我必须进行REST调用并将响应值与UI进行比较,那么步骤定义将如何构建?
在节点中创建 REST API 时,如何将来自对外部网站的请求的 http 响应流式传输到原始 api 调用?