首页 > 解决方案 > 异步上传多个文件时浏览器/服务器挂起?

问题描述

可能有一个简单的答案,但我不知道:

问题是我正在通过 XMLHttpRequests 上传多个文件,并从 for 循环中调用它。这会遍历必须上传的文件(使用 webkitdirectory 的整个文件夹)。如果我没有大量文件,那部分所有文件都可以工作,但我可能有多达 300 个或可能,可能永远不会超过 1000 个。我从 Github 项目中获得了原始代码:

UploadFolder,但我已经对其进行了一些编辑以满足我的需要。我认为关键代码仍然基本相同。

经过一些预处理后,有一个循环遍历要上传的文件列表并调用函数将文件上传到服务器:

for (var i = 0; i < picker.files.length; i++) {
    var file = picker.files[i];
    if (processflag[i] == false) {
        let lineitem = statusitem(file, "Skipped (.hidden file)");
        listing.insertAdjacentHTML('beforeend', lineitem);
    }
    else {
    sendFile(file);
    }
}

sendfile 函数很长,所以我只包含了可能是关键部分的内容:

sendFile = function(file) {

     var timestamp  = picker.dataset.timestamp;
     var formData = new FormData();

     // Set post variables 

     requestcounter = requestcounter + 1;
     formData.set('timestamp', timestamp);
     formData.set('counter', requestcounter);
     formData.set('total', total); 
     formData.set('webkitpath', file.webkitRelativePath);
     formData.set('file', file); // One object file


     var request = new XMLHttpRequest();

     request.responseType = 'json';

     // HTTP onload handler

     request.onload = function() {

         if (request.readyState === request.DONE) {

              if (request.status === 200) {

                 console.log(request.response);

                 // Does a bunch of post-processing stuff here
                 // .....
                 // .........

             }
             else {
                 // issue with request
             }
         }
     }

     // Do request
     request.open("POST", '/OrthancDev/UploadFolder');
     request.send(formData);
}

HTML 不是那么重要。

<div class="picker">
    <input type="file" id="picker" name="fileList" webkitdirectory multiple data-timestamp = "">
</div>

可能是最相关的部分,时间戳是动态设置的。

在服务器端,使用 PHP 对 POST 进行了一些相当复杂的处理,并且还执行了一些安装二进制文件,例如:

        $proc = proc_open(path_to_executable',[

        1 => ['pipe','w'],
        2 => ['pipe','w'],
        ],$pipes);
        $stdout = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        $stderr = stream_get_contents($pipes[2]);
        fclose($pipes[2]);
        proc_close($proc);
        . . . .

并将上传移动到服务器上的文件夹:

move_uploaded_file($file_tmp, $upload_path);

到服务器的 POST 包括:

-----------------------------19160542578905591423661131170
Content-Disposition: form-data; name="timestamp"
2020-05-09-15-44-36
-----------------------------19160542578905591423661131170
Content-Disposition: form-data; name="counter"
24
-----------------------------19160542578905591423661131170
Content-Disposition: form-data; name="total"
25
-----------------------------19160542578905591423661131170
Content-Disposition: form-data; name="webkitpath"
POST_T1_FS_TSE_SAG_2MM_12001/IM-0009-0025.dcm
-----------------------------19160542578905591423661131170
Content-Disposition: form-data; name="file"; filename="POST_T1_FS_TSE_SAG_2MM_12001/IM-0009-0025.dcm"
Content-Type: application/dicom

顺便说一句,上传的文件是否也会转到服务器上的 /tmp 目录?

问题是,对于一小部分文件,比如 8 个左右,一切似乎都可以正常工作,但是对于大量文件(例如,甚至只有 25 个),浏览器或服务器“挂起”。我正在使用 Apache 在 MAMP 服务器上运行所有内容,Apache 日志看起来很好,PHP 日志也是如此,我在那里没有看到任何错误。

它确实会快速连续地发送大量 AJAX 请求。

我不熟悉 FF 开发工具中的“计时选项卡”,但在发出最后一个请求时,“阻塞”时间显示为 1.38 秒。看起来所有文件都已上传到服务器,但浏览器此后对该虚拟主机无响应。

我认为这可能与连续触发那么多异步请求有关。我可以尝试同步发出这些请求,看看是否需要太长时间,或者使用某种承诺,或者限制活动异步请求的数量,但我不知道该怎么做。

我不确定这是否也是服务器端问题。单个文件大约 1MB,但可能更大,整个文件夹大约 256 MB,但也可能更大。

这显然是服务器端问题。有一个进程运行似乎挂起服务器的可执行文件,从而挂起浏览器:

$proc = proc_open($exec,[
    1 => ['pipe','w'],
    2 => ['pipe','w'],
],$pipes);
. . . .

从命令行运行大约需要 30 秒,但看起来所有文件都被发送到服务器并保存,所以看起来最后一个进程导致了问题。

CLI 的输出是:

XMIT: .........................................................................
I: Received Store Response (Success)
I: Sending file: /Users/sscotti/Desktop/newtelerad2/dicomtemp/DEV01/2020-05-10-05-44-14/UC5457343/T1_TSE_SAGITTAL_2MM_6001/IM-0003-0021.dcm
I: Converting transfer syntax: Little Endian Explicit -> Little Endian Explicit
I: Sending Store Request (MsgID 18, MR)

但大约 300 倍,每个文件 1 个。如果有一种很好的方法来解析来自 STDOUT 的输出(例如 I、W、E),那就太好了

标签: javascriptphpapacheasynchronousxmlhttprequest

解决方案


推荐阅读