NodeJs API отправляет пустой ответ при конвертации больших файлов - PullRequest
0 голосов
/ 21 мая 2019

В настоящее время я работаю над фрагментом кода, который загружает mp4 видео с моего localhost на сервер.Основным является то, что если видео является .mp4, оно загружается напрямую, в противном случае оно преобразуется в .mp4 и затем загружается.Я использую видео конвертер, используя handbrake-js.

Все работает отлично, за исключением крошечной части.Когда файл не такой большой, скажем, менее 70-80 Мб, он работает как шарм.Но проблема в больших файлах.Несмотря на то, что я явно вызываю res.end / res.send в обратном вызове .on(end), я получаю некоторый пустой ответ в своем угловом контроллере, даже до того, как преобразование завершено.Я заметил, что это происходит на 30-40% конверсии.Он имеет readystate, равный XMLHttpRequest.DONE, а также status = 200.

Вот код стороны узла:

try {
    if (fs.existsSync(uploadPath + filename.substring(0, filename.lastIndexOf('.')) + '.mp4')) {
        res.end('<b><i>' + filename + '</i></b> already exists in the directory.');
    }
    else {
        const fstream = fs.createWriteStream(path.join(cfg.tempStoragePath, filename));
        file.pipe(fstream);
        console.log("\nfile_type: " + file_type);
        filename = filename.substring(0, filename.lastIndexOf('.'));

        // On finish of the copying file to temp location
        fstream.on('close', () => {
            hbjs.spawn({
                input: cfg.tempStoragePath + filename + '.' + file_type,
                output: uploadPath + filename + '.mp4'
            })
                .on('error', err => {
                    // invalid user input, no video found etc
                    console.log('error! No input video found at: \n: ' + cfg.tempStoragePath + filename + '.' + file_type);
                    res.send('Conversion of the file, <b><i>' + filename + '</i></b>, from <b>.' + file_type + '</b>' + ' to <b>.mp4</b> failed because no input video was found at: \n: ' + cfg.tempStoragePath + filename + '.' + file_type);
                })
                .on('progress', progress => {
                    progress_percent = (Number(progress.percentComplete) * 2 <= 100) ? Number(progress.percentComplete) * 2 : 100;
                    eta = progress.eta.split(/[a-zA-Z]/);
                    minutes = ((+eta[0]) * 60 + (+eta[1])) / 2;
                    console.log('Percent complete: %d, ETA: %d ///// %s ==> mp4', progress_percent, minutes, file_type);
                })
                .on('end', end => {
                    console.log('Conversion from .' + file_type + ' to .mp4 complete.');
                    //delete the temp file
                    fs.unlink(cfg.tempStoragePath + filename + '.' + file_type);
                    let new_path = uploadPath + filename + '.mp4';
                    let stat = fs.statSync(new_path);
                    console.log(`Upload of '${filename}' finished`);
                    if(Number(progress_percent) === Number(100))
                        res.send('The file, <b><i>' + filename + '</i></b>, has been converted from <b>.' + file_type + '</b>' + ' to <b>.mp4</b> complete.');
                    })
                });
            }
    } 

    catch (err) {
        res.end(err);
    }

Ниже приведена часть моего углового контроллера:


request = new XMLHttpRequest();
request.onreadystatechange = function () {
    if (request.readyState === XMLHttpRequest.DONE && request.status === 200) {
        showConversionModal('<p>' + request.responseText + '</p>', 'done');
    }
};
showSomeModal('something');
request.open("POST", client.clientHost + ":" + client.clientPort + "/uploadVideoService");
formData = new FormData();
formData.append("file", files[0], files[0].name);
request.send(formData);

ПРИМЕЧАНИЕ : Все данные, которые делают console.log() внутри узла, соответствуют ожидаемым.И даже res.end/send отлично работает для небольших файлов, которые занимают меньше времени.Но проблема возникает только для тех, чье преобразование занимает больше времени, чем файлы меньшего размера.

Кроме того, цикл if, который проверяет существующий файловый сценарий, не работает должным образом для этих больших файлов.Я думал, по крайней мере, это должно сработать, потому что это даже не входит в часть handbrake.Но это не так.

И в браузере я получаю эту ошибку:

Failed to load resource: net::ERR_CONNECTION_RESET

, которая указывает на request.send(formData);линии, и я также попробовал почти все решения из этой статьи SO , но безрезультатно.Но, тем не менее, преобразование происходит нормально.

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

ОБНОВЛЕНИЕ: Я попытался использовать отладчик в VS Code и увидел, что точки останова справедливо достигают res.end() внутри цикла if, который проверяетдля существующего файлового сценария, но по какой-то странной причине угловой контроллер не реагирует на это.И это происходит только для больших файлов.

1 Ответ

0 голосов
/ 23 мая 2019

Я понял это сам после долгого времени. Оказывается, что-то вроде буфера в Busboy.

Здесь я использовал для связи busboy и express следующим образом:

app.use(busboy());

Просто установив поле с именем highWaterMark в произвольный размер, который будет больше, чем размер файла, добился цели.

app.use(busboy({
    highWaterMark: 2048 * 1024 * 1024, // Set buffer size in MB
}));

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...