NodeJs API在转换较大文件时发送空白响应

时间:2019-05-21 08:34:57

标签: javascript node.js xmlhttprequest

我目前正在编写一段代码,将mp4的视频localhost上传到服务器。基本的是,如果视频是.mp4,则直接上传,否则将其转换为.mp4,然后上传。我正在使用handbrake-js使用视频转换器。

除了一小部分,其他所有方法都工作正常。如果文件不是很大(例如小于70-80 Mb),则它就像一个魅力。但是问题出在更大的文件上。即使我在.on(end)回调中显式调用res.end / res.send,即使在转换完成之前,我的角度控制器也会收到一些空白响应。我注意到它发生在转化率的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);行,我也尝试了this SO article的几乎所有解决方案,但效果不佳。但仍然可以正常进行转换。

PS :另外请注意,即使对于较大的文件,转换和上传也不会出现问题,这只是我在客户端收到的响应,这让我很头疼。

更新:我尝试在VS Code中使用调试器,发现断点正好碰到res.end()循环中的if,该循环检查现有文件情况,但是由于某些奇怪的原因,角度控制器没有对此做出反应。而且这仅适用于较大的文件。

1 个答案:

答案 0 :(得分:0)

我想了很久。原来Busboy中有一个缓冲区。

在这里,我曾经这样链接busboyexpress

app.use(busboy());

只需将名为highWaterMark的字段设置为大于文件大小的任意大小即可。

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

我不知道是什么引起了这个问题,或者我不知道新领域可以解决什么,但是,我所知道的只是可以解决的。有人可以详细说明这一点会有所帮助。