以流方式从 HTTP 服务器接收 Web 浏览器中的二进制数据

Receive binary data in web browser from HTTP server in a streaming style

我正在寻找一个仅客户端 JavaScript 的解决方案,它可以从 HTTP 服务器接收一个大的二进制文件以流式传输到我的 Web 客户端,这样我就可以立即响应无需等待所有数据加载到内存中即可获取数据包,我什至可以在处理完每个数据后丢弃数据,以减少内存占用。

我在网上搜索了一下,发现似乎无法通过 XMLHttpRequest 实现,原因有二(引自 this article),

我想知道这是否可以通过 websocket 实现,是否有任何好的开源已经解决了这个问题?我发现一些似乎相关的,例如 Oboe.js and Binary.js,但它要么处理 JSON 流式传输,要么需要服务器端支持。

使用 XMLHttpRequest 无法满足我的所有请求。但是,通过一些技巧,我可以在块二进制数据到达后读取它。一般来说,将 minetype 覆盖为 'text/plain; charset=x-user-defined',它将二进制数据作为文本流式传输,一旦一个包准备就绪,我就可以获取它并将其转换为 arrayBuffer。

var xhr = new XMLHttpRequest();
var streamOffset = 0;

xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.open("GET", url, true);
xhr.send();
xhr.onreadystatechange = function () {
    var textBuffer = xhr.responseText;
    var arrayBuffer = textToArrayBuffer(textBuffer, streamOffset);
}
function textToArrayBuffer(textBuffer, startOffset) {
    var len = textBuffer.length - startOffset;
    var arrayBuffer = new ArrayBuffer(len);
    var ui8a = new Uint8Array(arrayBuffer, 0);
    for (var i = 0, j = startOffset; i < len; i++, j++)
        ui8a[i] = (textBuffer.charCodeAt(j) & 0xff);
    return arrayBuffer;
}

虽然,通过这种方式我可以以流的方式获取二进制数据,但在处理完每个块之后,它不能被丢弃,直到请求完成。无论如何,这让我有机会在二进制数据到达时立即对其进行处理。

如今,您可以使用 Fetch API.

fetch() 的结果包含一个名为 body 的 属性,它是一个可以用来读取结果的 ReadableStream

fetch('https://example.fake/movies.csv')
  .then((fetchedData) => {
    const reader = fetchedData.body.getReader();
    readChunks(reader);
  });


function readChunks(reader) {
  reader.read().then(({ done, value }) => {
    if (done) {
      console.log('done reading', value);
      return;
    }

    console.log('read chunk', value);
    readChunks(reader);
  });
}