下载大文件或显示错误

Download a large file or show error

在我们正在开发的网站上,我们有一个下载 link,必须提供给用户。但是,在获取 url 时,服务器可以在 JSON 中提供错误消息(然后将设置适当的 headers 和适当的 http 状态代码)或提供文件。

目前,我们正在使用 iframe 下载此文件,但这会阻止我们查看错误消息。虽然原则上可以做到这一点,但不能做到 cross-domain 并且读取错误数据似乎在浏览器之间有所不同(因为浏览器会将 json 解释为 html 并创建html 个标签)

我考虑过使用 xmlhttprequest2 下载文件并将其提供给用户,但是下载的文件可能很大,因此必须流式传输给用户。

因此,我正在寻找一种方法来根据 http 状态代码下载文件或读取错误消息。

API 设置

我可以根据自己的意愿更改 API,但是 API 被设计为 public API 并且被设计为 REST API。这意味着 API 应该尽可能简单,并且使特定 client-side 代码正常工作的变通方法不应该对其他 client-side 造成任何干扰(因此 API和 client-side 代码是解耦的)。

正在下载的文件在服务器上已加密,只能通过URL中给出的信息解密。因此,分块传输是困难的,因为提取分块需要服务器解密整个文件。

the appropriate headers and an appropriate http status code will then be set

如果该陈述是正确的,您可以对 Cross-site 请求使用与 preflighted requests 相同的概念。预检请求首先使用 OPTIONS 方法向其他域上的资源发送 HTTP 请求,以确定实际请求是否可以安全发送。

在您的情况下,您可以手动发送 HEAD 请求,而不是自动发送 OPTIONS 请求。 HEAD 方法与 GET 相同,只是服务器在响应中不 return 一个 message-body。响应 HEAD 请求的 HTTP headers 中包含的信息应与响应 GET 请求而发送的信息相同。由于您只获取 headers 而不是 body,因此对于大文件甚至任何文件都没有问题,除了 headers.

之外没有任何内容被下载

然后,您可以读取这些 headers 甚至状态代码,并根据此手动预检请求的结果,决定是否应该将文件流式传输给用户或获取错误消息,如果您遇到错误。

在不了解您的项目的情况下使用状态代码的基本实现如下:

function canDownloadFile(url, callback)
{
  var http = new XMLHttpRequest();
  http.open('HEAD', url);
  http.onreadystatechange = function() {
    if (http.readyState === XMLHttpRequest.DONE) {
      callback(http.status);
    }
  };

  http.send();
}

var canDownloadCallback = function (statusCode) {
  if (statusCode === 200) {
    // The HEAD request returned an OK status code, the GET will do the same,
    // let's download the file...
  } else {
    // The HEAD request returned something else, something is wrong,
    // let's fetch the error message and maybe display it...
  }
}

您可以使用单个请求,return 响应作为 Blob,检查 Blob.type 以确定在何处利用 FileReader .result 检索 JSON 来自 Blob 的文本并显示错误消息,或使用 URL.createObjectURL

设置 <img> 元素的 src
var result = document.querySelector("div");

fetch("/path/to/resource")
.then(response => response.blob())
.then(blob => {
  if (blob.type === "application/json") {
    var reader = new FileReader();
    reader.onload = (e) => {
      result.innerHTML = JSON.parse(e.target.result).error
    };
    reader.readAsText(blob);
  } else {
    var img = document.createElement("img");
    img.src = URL.createObjectURL(blob);
    result.appendChild(img);
  }
});

plnkrhttp://plnkr.co/edit/wrzLNm1Sp4k1mfNrYOlQ?p=preview

您可以 return iframe JS 代码,它会通过 postMessage 向父 window 发送消息,这样您就可以捕获主机 window 中的错误。跨域不会有任何问题,内容可以像以前一样轻松地流式传输到浏览器。