Ajax - получить размер файла перед загрузкой - программирование

Ajax - получить размер файла перед загрузкой

В принципе, я хочу выяснить, должен ли я загружать файл с использованием AJAX, в зависимости от того, насколько большой размер файла.

Я думаю, этот вопрос можно было бы также перефразировать как: Как получить только заголовок запроса ajax?


EDIT: ultima-rat0 в комментариях рассказали мне о двух уже заданных вопросах, которые, по-видимому, совпадают с этими, Они очень похожи, но оба хотят jQuery. Я хочу использовать не-jQuery-решение.

4b9b3361

Ответ 1

Вы можете получить данные заголовка ответа XHR вручную:

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

Эта функция получит размер файла запрашиваемого 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.");
});

Ответ 2

Иногда 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);

Ответ 3

Если запрос HEAD невозможен:

Решение 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();
  }
);

Ответ 4

1) Если нужны только заголовки, "HEAD" всегда следует отдавать предпочтение "GET" из-за простой, но малоизвестной детали: даже если вы используете "GET" и сразу прервитесь на readyState === 2 (как предложено другими ответы), вы уже получили не только заголовки, но и полный первый блок информации (заголовки + часть тела), который может варьироваться по размеру, но обычно размер передачи будет по меньшей мере удвоен. Используя вместо этого "HEAD", вы можете быть уверены, что будут переданы только заголовки.

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 НЕ запрещен, когда применяется какой-либо тип кодирования (как предлагается в некоторых комментариях). Но будьте осторожны, что Content-Length будет обычно иметь размер декодированного тела (даже если это не должно). Это может быть предотвращено многими различными способами, но это на стороне сервера.