From 1663d9909d65f481c73c4004245cbe2828b124b2 Mon Sep 17 00:00:00 2001 From: alan <67932758+alan16742@users.noreply.github.com> Date: Thu, 19 Sep 2024 08:38:42 +0800 Subject: [PATCH] upload large file --- front-end/index.html | 129 +++++++++++++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 35 deletions(-) diff --git a/front-end/index.html b/front-end/index.html index 6ada1ee7..a7fba03d 100644 --- a/front-end/index.html +++ b/front-end/index.html @@ -1236,10 +1236,10 @@ upload.innerHTML = ""; upload.innerHTML += ` `; @@ -1563,6 +1563,7 @@ } const paginatedUpFileList = paginate(upFileList, pageSize); + function sendPage(pageIndex = 0) { if (pageIndex >= paginatedUpFileList.length) { return; @@ -1590,48 +1591,106 @@ } sendPage(0); - function uploadFileWithProgress(file, uploadUrl) { - const xhr = new XMLHttpRequest(); + async function uploadFileWithProgress(file, uploadUrl) { + const chunkSize = 1024 * 1024 * 10; + const fileSize = file.size; + let uploadedBytes = 0; + let start = 0; const progressDiv = document.getElementById("uploadDiv"); - + const progressText = document.createElement("div"); const progressContainer = document.createElement("div"); - progressContainer.className = "progress-container"; progressDiv.appendChild(progressContainer); - - const progressText = document.createElement("div"); - progressText.className = "progress-text"; progressContainer.appendChild(progressText); - xhr.upload.onprogress = function (event) { - if (event.lengthComputable) { - const percentComplete = Math.round( - (event.loaded / event.total) * 100 - ); - const progressBar = - "[" + - "=".repeat(percentComplete / 5) + - " ".repeat(20 - percentComplete / 5) + - "]"; - progressText.textContent = `${file.name}: ${progressBar} ${percentComplete}%`; + while (start < fileSize) { + try { + await uploadChunk(start); + start = Math.min(start + chunkSize, fileSize); + } catch (error) { + if (!(await handleUploadError(error))) { + progressText.innerHTML += " Upload failed!"; + return; + } } - }; + } - xhr.onload = function () { - if (xhr.status === 200 || 201) { - progressText.textContent += " Upload complete!"; - } else { - progressText.innerHTML += " Upload failed!"; - } - }; + progressText.innerHTML += " Upload completed!"; - xhr.onerror = function () { - progressText.innerHTML += - " An error occurred during the upload."; - }; + async function uploadChunk(start) { + const xhr = new XMLHttpRequest(); + const end = Math.min(start + chunkSize, fileSize); + const chunk = file.slice(start, end); + + xhr.open("PUT", uploadUrl); + xhr.setRequestHeader( + "Content-Range", + `bytes ${start}-${end - 1}/${fileSize}` + ); + + return new Promise((resolve, reject) => { + xhr.onloadend = () => { + if (xhr.status >= 200 && xhr.status < 300) { + uploadedBytes = end; + updateTotalProgress(); + resolve(xhr.status); + } else { + reject(xhr.status); + } + }; - xhr.open("PUT", uploadUrl); - xhr.send(file); + xhr.upload.onprogress = (event) => { + if (event.lengthComputable) { + uploadedBytes = start + event.loaded; + updateTotalProgress(); + } + }; + + xhr.send(chunk); + }); + } + + async function handleUploadError(error) { + let retryCount = 10, + delayTime = 1; + while (retryCount > 0) { + retryCount--; + if (error === 416) { + await new Promise((resolve) => + sendRequest("GET", uploadUrl, null, null, (data) => { + start = parseInt( + JSON.parse(data).nextExpectedRanges[0].split("-")[0] + ); + resolve(); + }) + ); + return true; + } else { + await new Promise((resolve) => + setTimeout(resolve, Math.min((delayTime *= 2) * 1000, 32000)) + ); + try { + await uploadChunk(start); + return true; + } catch (err) { + error = err; + } + } + } + return false; + } + + function updateTotalProgress() { + const percentComplete = Math.round( + (uploadedBytes / fileSize) * 100 + ); + const progressBar = + "[" + + "=".repeat(percentComplete / 5) + + " ".repeat(20 - percentComplete / 5) + + "]"; + progressText.textContent = `${file.name}: ${progressBar} ${percentComplete}%`; + } } }