Загрузка блобов в качестве загрузки нескольких частей вызывает сеть:: ERR_FILE_NOT_FOUND в Chrome после 500 МБ

У меня очень странная проблема только в Google Chrome и Chromium.

Фон:

Я загружаю файлы на свой сервер, используя метод многофакторной загрузки, что означает, что я разбиваю файлы на куски размером 10 МБ и отправляю каждый фрагмент на сервер. Это работает безупречно во всех браузерах с файлами любого размера, проблема началась, когда мне нужно было зашифровать каждый фрагмент.

Для шифрования я использую CryptoJS, и, прежде чем загружать кусок, я зашифровываю его и получаю результирующий Blob для загрузки, это отлично работает в Chrome, когда я загружаю менее 50 кусков (50 капотов, всего 500 мб), после чего я получаю a POST http://(...) net::ERR_FILE_NOT_FOUND.

Как ни странно, это работает во всех других браузерах, включая Opera, которая в настоящее время является в основном Chrome, за исключением Chrome и Chromium. Я тестировал его на IE, Firefox, Edge, Safari, Opera, Chrome и Chromium.

Ниже вы можете увидеть, как работает мой код, чтобы вы, ребята, могли подумать, что это не настоящий код, который я использую в приложении, а скорее это тестовый код, который я написал, который дает тот же результат.

Вместо того, чтобы получать фрагмент (File.slice) файла, который я собираюсь загрузить как кусок и зашифровать его, чтобы получить Blob, я собираюсь создать поддельный Blob с размером мой кусок. Я положил setTimeout, чтобы имитировать время, необходимое для шифрования blob. Как я уже говорил, я получаю тот же результат, что и мой реальный код, делая это:

function uploadNext(prevResponse) {  
    if (currentPart == totalPartsFile)
        return;

    //var chunk = getNextChunk();
    var totalSize = file.size;

    setTimeout(function() {
        var blob = new Blob([new ArrayBuffer(constants.chunkSize)], {
            type: 'application/octet-string',
            name: file.name
        });

        console.log(blob);

        blob.encrypted = true;
        blob.key = encryptionKey;
        blob.mimeType = file.mimeType;
        blob.name = file.name;
        blob.originalFileSize = originalFileSize || file.size;

        uploadFile(objectId, currentPart, blob, totalSize, prevResponse, function(resp) {
            uploadNext(resp);
        });
    }, 1000);
}

Итак, приведенный выше код - это то, где генерируется мой blob, ниже находится загружаемая часть:

function uploadFile (objectId, index, blob, totalSize, prevResponse, callback) {

    var format = "encrypted";
    var params = "?format=" + format + (format === "encrypted" ? "&encoding=base64" : "");
    var endPoint = constants.contentServiceUrl + resourceService.availableResources.addContents.link.split(':objectId').join(objectId) + params;

    var formData = new FormData();

    formData.append("totalFileSizeBytes", totalSize);
    formData.append("partIndex", index);
    formData.append("partByteOffset", previousOffset);
    formData.append("chunkSize", blob.size);
    formData.append("totalParts", totalPartsFile);
    formData.append("filename", blob.name);

    if (currentPart != 0) {
        formData.append("uploadId", prevResponse.uploadId);
        formData.append("bucket", prevResponse.bucket);
    }

    if (finalChunk) {
        for (var key in etags1) {
            formData.append("etags[" + key + "]", etags1[key]);
        }
    }

    formData.append("data", blob);

    previousOffset += blob.size;

    var request = {
        method: 'POST',
        url: endPoint,
        data: formData,
        headers: {
            'Content-Type': 'multipart/form-data'
        }
    }

    $http(request)
        .success(function(d) {
            _.extend(etags1, d.etags);
            console.log(d);
            callback(d);
        })
        .error(function(d) {
        console.log(d);
    });                                                
}

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

В этом примере я использую модуль AngularJS '$http, но я пробовал с чистым XMLHttpRequest, и я получил тот же результат.

Как я уже сказал, я получаю только POST http://(...) net::ERR_FILE_NOT_FOUND с файлами размером больше 499mb (50+ кусков) и только в Chrome.

Я размещаю это здесь, поскольку искал решение, но я не мог найти ничего, связанного с этой проблемой, ближайшая вещь, которую я нашел в Интернете, была эта проблема на форуме проекта Chromium:

https://code.google.com/p/chromium/issues/detail?id=375297

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

Спасибо за ответы заранее.

Ответы

Ответ 1

Хром может выделять только 500 МБ для любого blob, поэтому, если вы попытаетесь выделить 500 Мбайт + 1 байт, он будет явно игнорировать этот байт, чтобы решить эту проблему, вам придется читать файл в кусках 499mb, а затем вам придется объединить файл на сервере.

Или вы можете попробовать что-то вроде ZipJS, а затем загрузить zip, это сработало для меня.

    var zip = new JSZip();
    zip.file("file1", "content1");
    zip.file("file2", "content2");

Ответ 2

В последних исходных файлах хрома я обнаружил пределы blob.

  • ChromeOS:

    • Рам - 20%
    • Диск - 50% Примечание. Диск является пользовательским разделом, поэтому операционная система все еще может функционировать, если она заполнена.
  • Android:

    • ОЗУ - 1%
    • Диск - 6%
  • Desktop:
    • Рам - 20% или 2 ГБ, если x64.
    • Диск - 10%

ссылка хрома репо: https://cs.chromium.org/chromium/src/storage/browser/blob/blob_memory_controller.cc?l=63

Ответ 3

Кажется, это проблема с Firebug. Попытайтесь отключить его. Это работает для меня.

браузер Firefox. У меня возникла проблема, когда я загружал файл кусками. Я отключил плагины и утечку памяти не появляется. Возможно, это поможет вам

Для Chrome все работает нормально.