如何将对 REST 调用的响应分成小块?
How to chop up response to REST-call into small chunks?
我正在 node.js 开发网络应用程序。该应用程序的某些部分允许用户访问 upload/retrieve 文件。我使用 'SoftLayer Object Storage'-服务来托管这些文件。但是,在提供视频时,它在 Chrome/Firefox/Android 上的 HTML5-video 元素中播放正常,但在 Safari/iOS.
上却没有
为了深入了解这个问题,我 运行 在另一个 Whosebug 上进行了解释-post:
iOS devices expect the videos to arrive in small chunks. So for instance a streaming server is able to do this. However, a blob server just hands the video as a blob which is not what the iOS device expects. Some browsers are smart enough to handle this but others not.
为了检查这个解释是否有意义,我尝试流式传输相同的 mp4 文件。为了做到这一点,我基于 this Whosebug-post 上接受的答案,这实际上在所有浏览器和平台上都运行良好,这让我相信我上面引用的解释实际上是正确的。
不幸的是,此流式代码在我的情况下不起作用,因为该文件托管在 SoftLayer 上,而 accepted 假定该文件存在于服务器的文件系统上。我通过 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);
});
});
显然,此代码不会 "stream" 视频,只是将整个视频一次发送给客户端。使用此代码,视频无法在 Safari 中播放。
我想以某种方式逐块发送视频(就像上面讨论的 Whosebug-answer 中的情况一样)而不是一次全部发送,但是当通过REST 请求。我确实注意到 API 允许在执行 GET 请求时提供可选的 "Range" 参数,但我不确定如何利用它来发挥我的优势。
最后我还想提一下,我不认为视频的编码是问题所在。我正在使用此视频 http://www.w3schools.com/html/mov_bbb.mp4,当我在 iOS/safari 上输入 link 时,效果很好。
问题是您正在尝试 pipe
来自 API 的整个响应,包括状态和 headers 等等。
相反,您需要将响应 body 转换为可读流并将其通过管道传递给响应。要将 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);
}
});
});
});
我正在 node.js 开发网络应用程序。该应用程序的某些部分允许用户访问 upload/retrieve 文件。我使用 'SoftLayer Object Storage'-服务来托管这些文件。但是,在提供视频时,它在 Chrome/Firefox/Android 上的 HTML5-video 元素中播放正常,但在 Safari/iOS.
上却没有为了深入了解这个问题,我 运行 在另一个 Whosebug 上进行了解释-post:
iOS devices expect the videos to arrive in small chunks. So for instance a streaming server is able to do this. However, a blob server just hands the video as a blob which is not what the iOS device expects. Some browsers are smart enough to handle this but others not.
为了检查这个解释是否有意义,我尝试流式传输相同的 mp4 文件。为了做到这一点,我基于 this Whosebug-post 上接受的答案,这实际上在所有浏览器和平台上都运行良好,这让我相信我上面引用的解释实际上是正确的。
不幸的是,此流式代码在我的情况下不起作用,因为该文件托管在 SoftLayer 上,而 accepted 假定该文件存在于服务器的文件系统上。我通过 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);
});
});
显然,此代码不会 "stream" 视频,只是将整个视频一次发送给客户端。使用此代码,视频无法在 Safari 中播放。
我想以某种方式逐块发送视频(就像上面讨论的 Whosebug-answer 中的情况一样)而不是一次全部发送,但是当通过REST 请求。我确实注意到 API 允许在执行 GET 请求时提供可选的 "Range" 参数,但我不确定如何利用它来发挥我的优势。
最后我还想提一下,我不认为视频的编码是问题所在。我正在使用此视频 http://www.w3schools.com/html/mov_bbb.mp4,当我在 iOS/safari 上输入 link 时,效果很好。
问题是您正在尝试 pipe
来自 API 的整个响应,包括状态和 headers 等等。
相反,您需要将响应 body 转换为可读流并将其通过管道传递给响应。要将 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);
}
});
});
});