发送200个响应标头后发送HTTP请求失败的方法

时间:2019-02-04 14:38:22

标签: node.js http express websocket xmlhttprequest

简短的问题:

当有大量数据要发送时,考虑一个持久响应的情况。然后,服务器需要在完成所有数据生成之前将数据传输回客户端。如果我正确的话,这需要在一开始就发送http标头。但是,如果在流式传输数据期间出现异常,将其传达给客户端的最佳方法是什么?理想情况下,我希望浏览器中的XMLHttpRequest由于非200响应代码或类似原因而失败。我正在服务器上使用nodejs express。

详细问题:

我需要将大量数据流式传输到浏览器中,大约700Mb。我需要在生成数据时将数据流式传输到客户端,而不是将其缓冲在服务器上,因为否则服务器将耗尽内存。

这是我在浏览器端使用的代码。

return new Promise((resolve, reject) => {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', this.getDownloadLink(), true);
  xhr.setRequestHeader('authorization', this.getAuthToken());
  xhr.responseType = 'blob';
  xhr.onload = () => {
    if (xhr.status === 200) {
      saveAsFile(xhr.response);
      resolve();
    }
    else {
      reject(xhr.response);
    }
  };
  xhr.onerror = () => {
    reject(xhr.response);
  };
  xhr.send();
});

我正在使用XHR,因为我需要设置授权标头。浏览器可以在保存文件之前保留700Mb的存储空间,这可能是因为它在磁盘上存储了Blob,但这不是阻止程序。

所以我开始传送,不知道它将以成功结束。如果中间的数据生成失败,我该如何从服务器到客户端传达错误? 我希望上面的承诺在服务器发生故障时拒绝。

这是我在服务器上使用的代码的一部分:

response.status(200);
db.stream
.on('data', data => response.write())
.on('error', error => {
  // this does not work as intended
  response.status(500);
  response.end(error.message);
})

如您所见,它是在发送标头之后通过管道传递数据。

2 个答案:

答案 0 :(得分:1)

头已发送,仅此而已,没有转折点。客户端不会一次收到整个700mb的http响应,而是逐个接收。如果我们以纯文本形式读取http响应,则它的第一部分将是元数据(状态等),并且标题将逐行显示。这就是为什么在您已经发送200之后就无法发送500状态的原因。不是因为Node.js或express不允许这样做,而是因为作为通信协议的http本身不允许这样做。 我可以看到您正在使用http传输此数据量,因为您需要业务逻辑的标头。我建议您看一下socket.io。它允许您从查询字符串中获取一些有用的信息/数据,您可以在其中将使用标头的数据作为查询参数,并通过socket.io节点api访问它!非常方便地执行任何身份验证或相关工作。 希望我能帮助您!

答案 1 :(得分:1)

有一种在响应结束时发送“标头”的方法。它们称为Trailers

您可以使用nodejs Response object发送它们。