Загрузка больших файлов с помощью вызова ajax выдает «Ошибка сети» в браузере Chrome - PullRequest
0 голосов
/ 27 сентября 2018

Итак, я пытаюсь загрузить zip-файл с помощью ajax-вызова для моего API.API отвечает с помощью байтового массива в кодировке 64.Теперь для большинства загрузок это работает просто отлично, но когда размер zip-файла становится слишком большим, он начинает давать сбой в Chrome.Прекрасно работает во всех других браузерах.Из того, что я обнаружил при переполнении стека, это известная проблема в Chrome, и люди предложили использовать BLOB-объекты.Дело в том, что я использую капли и все еще имею проблему.Вот мой код для обработки загрузки.Я использую это для загрузки pdf и zip файлов, передавая разные значения для contentType.Кто-нибудь сталкивался с этим вопросом раньше?Есть ли какие-нибудь обходные пути или сценарии, которые я могу добавить на страницу, чтобы решить эту проблему?

// data is base 64 encoded byte array
function download(data, filename, contentType) {

    var byteCharacters = atob(data);
    var byteNumbers = new Array(byteCharacters.length);
    for (var i = 0; i < byteCharacters.length; i++) {
        byteNumbers[i] = byteCharacters.charCodeAt(i);
    }
    var byteArray = new Uint8Array(byteNumbers);
    var blob = new Blob([byteArray], { type: contentType });

    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        // IE / edge workaround
        window.navigator.msSaveOrOpenBlob(blob, filename);
    } else if (navigator.userAgent.indexOf("Firefox") > 0) {
        var a = window.document.createElement('a');
        a.download = filename;
        a.style.cssText = "display: none";
        a.target = "_blank";
        // Append anchor to body.
        document.body.appendChild(a);
        a.href = "data:" + contentType + ";base64," + data;
        a.click();

        // Remove anchor from body
        document.body.removeChild(a);
    } else //Chrome, safari, etc
        {
            var a = document.createElement("a");
            a.style = "display: none";
            var url = window.URL.createObjectURL(blob);
            a.href = url;
            a.download = filename;
            a.click();
            window.URL.revokeObjectURL(url);
        }
}

Ответы [ 4 ]

0 голосов
/ 08 октября 2018

В дополнение к описанным выше методам решения вы также можете попытаться установить свойство maxRequestLength в файле web.config.

<system.web>
    ...
    <httpRuntime targetFramework="4.5.1" maxRequestLength="51200" executionTimeout="30" />
    <!-- for 50 MB set maxRequestLength="51200"-->
</system.web>

Надеюсь, это поможет ...

0 голосов
/ 05 октября 2018

Кажется, это ошибка.Тем временем, когда он будет решен, вот что вы могли бы сделать.

Разделите файл на более мелкие части и сделайте много запросов AJAX, а затем, когда все будет загружено, восстановите исходную сторону клиентского файла путем объединения частей.Оттуда действуйте как обычно.

0 голосов
/ 05 октября 2018

Проблема с загрузкой больших двоичных объектов в основном связана с утечкой памяти.Думаю, какой-то дополнительный код может решить эту проблему.

  1. Ваш большой двоичный объект хранится в памяти, и если он очень большой, это плохо, потому что процесс браузера имеет ограничение доступной памяти.Это может решить indexedDB indexeddb пример . Вы должны добавить BLOB-объект в indexedDB, а затем удалить его из него.Когда вы пишете BLOB-объект в indexeddb, браузер создает кешированный файл в файловой системе, и с этого момента ваш BLOB-объект будет храниться в файловой системе, как файл.И это действие освободит много памяти.

  2. Когда вы создадите ObjectUrl, у вас будет дополнительная ссылка большого двоичного объекта в памяти, и сборщик мусора удалит ее только при событии выгрузки документа.Поэтому вам нужно отозватьObjectURL.

var previousBlob = null;

downloadFile(source, filename) {
   if(previousBlob){
     URL.revokeObjectURL(previousBlob);
     previousBlob = null;
   }
   //.. do stuff
}

PS

IndexedDB помог мне решить одну ошибку Chrome. ВВ браузере Chrome вы не можете создать 1000 BLOB-объектов (всего на всех открытых вкладках), поэтому я решаю эту проблему, записывая BLOB-объекты в indexeddb. Потому что BLOB-объекты стали файлами, и количество BLOB-объектов на них не распространяется.Вы можете увидеть результат самостоятельно в утилите firefox «about: memory», который является лучшим инструментом для предварительной памяти (лучше, чем в других браузерах)

0 голосов
/ 01 октября 2018

API отвечает байтовым массивом с кодировкой 64

Почему?Я предлагаю вам добавить метод, который будет отвечать чисто двоичными zip-файлами.

Когда установлено xhr.responseType = "blob";, и просто сохранить его, как вы делаете это для Chrome.

Если вы хотитеоставьте свой API таким, как есть, попробуйте избавиться от Array и сразу же заполните Uint8Array.

UPD .Я проверил это на своем Chrome 69 под Ubuntu 18.04 с 16 ГБ ОЗУ и обнаружил, что Chrome не позволяет мне загружать более 1000 мегабайт таким образом.

Какого размера файл вы пытаетесь загрузить?

Проверьте это самостоятельно (не забудьте убедиться, что ничто не заблокирует загрузку):

function getBlob(size) {
    let u8a = new Uint8Array(size);
    for (var i = 0; i < size; i++) {
        u8a[i] = 33 + Math.floor(Math.random() * 5)
    }
    return new Blob([u8a]);
}

function downloadFile(source, filename) {
	if (source instanceof (File, Blob)) {
		filename = source.name || filename;
		source = URL.createObjectURL(source);
	}
	let link = document.createElement("a");
	link.style.display = "none";
	link.href = source;
	link.download = filename || "blob.bin";

	document.body.appendChild(link);

	link.click();

	setTimeout(function () {
		document.body.removeChild(link);

		URL.revokeObjectURL(source);
	}, 3000);
}
Size (MB): <input id="in" type=number min=1 max=3000>
<button onclick="downloadFile(getBlob(1024(+document.getElementById('in').value)))">download</button>
*1024*
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...