简体   繁体   English

在使用 net::ERR_FILE_NOT_FOUND 成功上传一些成功后,使用 Ionic4 和 Angular HttpClient 上传分块文件失败

[英]Uploading chunked file using Ionic4 and Angular HttpClient fails after some successful uploads with net::ERR_FILE_NOT_FOUND

i'm trying to upload a large file (500+Mb, but could be even bigger) to our php server, using an app written in Ionic4+Angular+Cordova, on an emulator with Android 10. I set up a system to upload the file in chunks.我正在尝试将一个大文件(500+Mb,但可能更大)上传到我们的 php 服务器,使用用 Ionic4+Angular+Cordova 编写的应用程序,在带有 Android 10 的模拟器上。我设置了一个系统来上传分块的文件。 It reads the file choosen by the user using THIS PLUGIN , chunk by chunk (5Mb per chunk).它使用此插件逐块读取用户选择的文件(每块 5Mb)。 Then it proceeds to send it to our server performing a POST request with Content-type multipart/form-data.然后它继续将它发送到我们的服务器,执行带有内容类型 multipart/form-data 的 POST 请求。 The file goes to server, server saves it, says "OK", then the app proceeds to send the following chunk.文件转到服务器,服务器保存它,说“OK”,然后应用程序继续发送以下块。 Everything works fine, for the first 25/29 chunks.对于前 25/29 个块,一切正常。 Then, the POST request fails with然后,POST 请求失败

POST http://192.168.1.2/work/path/to/webservices/uploadChunks.php net::ERR_FILE_NOT_FOUND

在此处输入图片说明

I tried:我试过:

  • starting at another point in the file instead of byte 0 - got the same error从文件中的另一个点而不是字节 0 开始 - 得到相同的错误
  • reading the file chunk by chunk, without making any POST request- could cycle the whole 500Mb file逐块读取文件,而不发出任何 POST 请求 - 可以循环整个 500Mb 文件
  • reading the file chunk by chunk and making the POST requests, but not sending the chunks with them - could execute every single call without any error, through the end of the file逐块读取文件并发出 POST 请求,但不随它们一起发送块 - 可以在文件末尾执行每个调用而不会出现任何错误
  • reading the file chunk by chunk and sending them to ANOTHER webservice - got the same error逐块读取文件并将它们发送到另一个网络服务 - 得到相同的错误
  • reading the file chunk by chunk and performing a POST request to another webservice, with content-type application/json and putting the formData object into the request body (not sure this is a valid test tho) - could execute every single call without any error, through the end of the file逐块读取文件并对另一个 Web 服务执行 POST 请求,内容类型为 application/json 并将 formData 对象放入请求正文中(不确定这是一个有效的测试) - 可以执行每个调用而没有任何错误, 通过文件末尾

Checking out memory snapshots taken in chrome inspector during different chunks upload did not show any sign of memory leak.检查在不同块上传期间在 chrome 检查器中拍摄的内存快照没有显示任何内存泄漏迹象。

The case was tested on a rather old device, where the same procedure caused the app to exit, without signaling any error (not even in logcat apparently).该案例在相当旧的设备上进行了测试,其中相同的过程导致应用程序退出,而没有发出任何错误信号(甚至在 logcat 中显然也没有)。

Here is the piece of code used to chunk and send the file:这是用于分块和发送文件的代码段:


const generatedName = 'some_name_for_file';

// Path obtained from fileChooser plugin
let path_to_file = 'content://com.android.externalstorage.documents/document/primary%3ADownload%2Ffilename.avi'

const min_chunk_size = (5 * 1024 * 1024);

// Converting path to file:// path
this.filePath.resolveNativePath(path_to_file).then((resolvedPath) => {

    return this.fileAPI.resolveLocalFilesystemUrl(resolvedPath);

}, (error) => {
    console.log('ERROR FILEPATH');
    console.log(error);
    return Promise.reject('Can not access file.<br>Code : F - ' + error);
}).then(
    (entry) => {

        path_to_file = entry.toURL();
        console.log(path_to_file);

        (entry as FileEntry).file((file) => {

            //Getting back to the zone
            this.ngZone.run(() => {

                // Re-computing chunk size to be sure we do not get more than 10k chunks (very remote case)
                let file_chunk_size = file.size / 10000;
                if (file_chunk_size < min_chunk_size) {
                    file_chunk_size = min_chunk_size;
                }

                //Total number of chunks
                const tot_chunk = Math.ceil(file.size / file_chunk_size);

                const reader = new FileReader();

                let retry_count = 0; //Counter to check on retries

                const readFile = (nr_part: number, part_start: number, length: number) => {

                    // Computing end of chunk
                    const part_end = Math.min(part_start + length, file.size);

                    // Slicing file to get desired chunk
                    const blob = file.slice(part_start, part_end);

                    reader.onload = (event: any) => {

                        if (event.target.readyState === FileReader.DONE) {

                            let formData = new FormData();

                            //Creating blob
                            let fileBlob = new Blob([reader.result], {
                                type: file.type
                            });

                            formData.append('file', fileBlob, generatedName || file.name);
                            formData.append('tot_chunk', tot_chunk.toString());
                            formData.append('nr_chunk', nr_part.toString());

                            // UPLOAD
                            const sub = this.http.post('http://192.168.1.2/path/to/webservice/uploadChunk.php', formData).subscribe({

                                next: (response: any) => {

                                    console.log('UPLOAD completed');
                                    console.log(response);

                                    retry_count = 0;

                                    if (response && response.status === 'OK') {

                                        //Emptying form and blob to be sure memory is clean
                                        formData = null;
                                        fileBlob = null;

                                        // Checking if this was the last chunk
                                        if (part_end >= file.size) {
                                            // END

                                            callback({
                                                status: 'OK'
                                            });
                                        } else {

                                            // Go to next chunk
                                            readFile(nr_part + 1, part_end, length);

                                        }

                                        //Clearing post call subscription
                                        sub.unsubscribe();

                                    } else {
                                        //There was an error server-side
                                        callback(response);
                                    }

                                },

                                error: (err) => {
                                    console.log('POST CALL ERROR');
                                    console.log(err);
                                    if (retry_count < 5) {
                                        setTimeout(() => {
                                            retry_count++;
                                            console.log('RETRY (' + (retry_count + 1) + ')');
                                            readFile(nr_part, part_start, length);
                                        }, 1000);
                                    } else {
                                        console.log('STOP RETRYING');
                                        callback({status:'ERROR'});
                                    }
                                }

                            });

                        }

                    };

                    //If for some reason the start point is after the end point, we exit with success...
                    if (part_start < part_end) {
                        reader.readAsArrayBuffer(blob);
                    } else {
                        callback({
                            status: 'OK'
                        });
                    }

                };

                //Start reading chunks
                readFile(1, 0, file_chunk_size);


            });
        }, (error) => {
            console.log('DEBUG - ERROR 3 ');
            console.log(error);
            callback({
                status: 'ERROR',
                code: error.code,
                message: 'Can not read file<br>(Code: 3-' + error.code + ')'
            });
        });
    }, (error) => {
        console.log('ERROR 3');
        console.log(error);
        return Promise.reject('Can not access file.<br>Code : 3 - ' + error);
    }
);

I can not figure out what is going wrong.我不知道出了什么问题。 Can someone help me debug this, or knows what could be going on?有人可以帮我调试这个,或者知道会发生什么吗?

Thank you very much.非常感谢。

I still do not know what caused this issue, but i resolved using a PUT request instead of a POST request, sending the raw chunk, and putting additional data in custom headers (something like "X-nr-chunk" or "X-tot-chunk").我仍然不知道是什么导致了这个问题,但我使用 PUT 请求而不是 POST 请求解决了这个问题,发送原始块,并将附加数据放在自定义标头中(类似于“X-nr-chunk”或“X-tot” -块”)。 Upload completed fine without the error message.上传完成,没有错误消息。

I also used the cordova-advanced-http plugin, but i do not think it made a difference here, since it did not work with the POST request, like the other method (httpClient).我还使用了cordova-advanced-http插件,但我认为它在这里没有什么不同,因为它与其他方法(httpClient)一样不适用于POST请求。

This has been tested on android only for now, not on iOS.目前仅在 android 上测试过,未在 iOS 上测试过。 I'll report if there is any problem.如果有问题,我会报告。 For now i consider this solved, but if you know what may have caused this problem, please share your thoughts.现在我认为这已经解决了,但是如果您知道可能导致此问题的原因,请分享您的想法。

Thanks everyone.谢谢大家。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM