javascript Ajax - 下载前获取文件大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17416274/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 08:14:43  来源:igfitidea点击:

Ajax - Get size of file before downloading

javascriptajaxhttp-headersfilesize

提问by MiJyn

Basically, I want to figure out whether I should download a file using AJAX, depending on how large the filesize is.

基本上,我想确定是否应该使用 AJAX 下载文件,具体取决于文件大小。

I guess this question could also be rephrased as: How do I get only the header of an ajax request?

我想这个问题也可以改写为:如何仅获取 ajax 请求的标头?



EDIT: ultima-rat0in the comments told me of two questions that had already been asked that apparently are the same as this one. They are very similar, but they both want jQuery. I want a non-jQuery solution to this.

编辑:评论中的ultima-rat0告诉我已经提出的两个问题,显然与这个问题相同。它们非常相似,但都需要 jQuery。我想要一个非 jQuery 解决方案。

回答by Hung Doan

You can get XHR response header data manually:

您可以手动获取 XHR 响应头数据:

http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method

http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-方法

This function will get the filesize of the requested URL:

此函数将获取请求的 URL 的文件大小:

function get_filesize(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open("HEAD", url, true); // Notice "HEAD" instead of "GET",
                                 //  to get only the header
    xhr.onreadystatechange = function() {
        if (this.readyState == this.DONE) {
            callback(parseInt(xhr.getResponseHeader("Content-Length")));
        }
    };
    xhr.send();
}

get_filesize("http://example.com/foo.exe", function(size) {
    alert("The size of foo.exe is: " + size + " bytes.");
});

回答by Ebrahim Byagowi

Sometimes HEAD can act differently than GET so I suggest something like this that aborts the request after getting Content-Lengthheader:

有时 HEAD 的行为可能与 GET 不同,所以我建议这样的事情在获取Content-Length标头后中止请求:

new Promise(resolve => {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', '/a.bin', true);
    xhr.onreadystatechange = () => {
        resolve(+xhr.getResponseHeader("Content-Length"));
        xhr.abort();
    };
    xhr.send();
}).then(console.log);

回答by hook2raiz2gswitch2cork

If HEAD request is not possible:

如果 HEAD 请求是不可能的:

The solution Ebrahim did only not work in firefox for me because context-length was not available for aborted request in firefox. So I used 'onprogress' event instead of 'onreadystatechange' event:

解决方案 Ebrahim 对我来说只是在 Firefox 中不起作用,因为上下文长度不可用于 Firefox 中的中止请求。所以我使用了 'onprogress' 事件而不是 'onreadystatechange' 事件:

new Promise(
  (resolve, reject) => {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onprogress = (event) => {
      if (event.lengthComputable) {
        resolve(event.total);
      } else {
        reject(new Error('No content-length available'));
      }
      xhr.abort();
    };
    xhr.send();
  }
);

回答by Ernesto Stifano

1) If only headers are needed, 'HEAD' should be always preferred over 'GET' because of a simple but not widely known detail: Even if you use 'GET' and immediately abort on readyState === 2 (as suggested by other answers), you will have already received not only the headers, but the full first chunk of information (headers + part of the body) that can vary in size, but usually transfer size will be at least doubled unnecessarily. Using 'HEAD' instead, you can be sure that only headers will be transferred.

1) 如果只需要头文件,'HEAD' 应该总是优先于 'GET' 因为一个简单但不广为人知的细节:即使你使用 'GET' 并立即在 readyState === 2 上中止(正如其他人所建议的那样)答案),您将不仅已经收到标题,而且还收到了完整的第一块信息(标题 + 正文的一部分),这些信息的大小可能会有所不同,但通常传输大小至少会不必要地翻倍。改用“HEAD”,您可以确保仅传输标头。

2) Content-Length header must be exposed by 'Access-Control-Expose-Headers' to be accessible client-side. If you are dealing with multiple origin resources and you are not sure if Content-Length has been exposed, to prevent exceptions, you can check that, inside an event handler, like this (or other many different ways):

2) Content-Length 标头必须由“Access-Control-Expose-Headers”公开才能在客户端访问。如果您正在处理多个源资源并且您不确定 Content-Length 是否已公开,为了防止异常,您可以在事件处理程序中进行检查,如下所示(或其他许多不同的方式):

let contentLength = null;

if (checkHeaders(e.target, ['*','Content-Length'])) {
    // YOU CAN ACCESS HEADER
    contentLength = parseInt(e.target.getResponseHeader("Content-Length"));
} else {
    // YOU CAN NOT ACCESS HEADER
    console.log('Content-Length NOT AVAILABLE');
}

function checkHeaders(request, headers) {
    return (headers.some(function (elem) {
        return (request.getResponseHeader("Access-Control-Expose-Headers").includes(elem));
    }));
}

3) Content-Length header IS NOT forbidden when any type of encoding is applied (as suggested in some comments). But, be careful that Content-Length will be usually the size of the decoded body (even if it should not). This can be prevented in many different ways, but it is a server-side consideration.

3) 当应用任何类型的编码时,不禁止 Content-Length 标头(如某些评论中所建议的)。但是,请注意 Content-Length 通常是解码主体的大小(即使它不应该)。这可以通过许多不同的方式来防止,但这是服务器端的考虑因素。