VorwortDas Hochladen von Dateien ist ein Problem, auf das Front-End-Entwickler während der Entwicklung häufig stoßen. Vielleicht können Sie verwandte Funktionen implementieren, aber denken Sie nach Abschluss, dass die Codeimplementierung etwas „unzureichend“ ist? Verstehen Sie Datei-Uploads wirklich? Wie kann ich große Dateien hochladen und Uploads bei Stromausfällen fortsetzen? Welche Formate werden üblicherweise für die Front-End- und Back-End-Kommunikation verwendet? Wie erfolgt die Fortschrittskontrolle beim Datei-Upload und wie wird sie auf dem Server implementiert? Als nächstes beginnen wir mit dem Erlernen der Nahkampfserie! ! ! Wenn es Mängel gibt, können Sie mir gerne Ihren Rat geben. Als nächstes folgen Sie der folgenden Abbildung zum Studieren und Diskutieren Sie sind bereit, los geht‘s! ! ! Frontend-StrukturSeitenanzeige Projektabhängigkeiten Backend-Struktur (Node + Express)Verzeichnisstruktur Einfache Kapselung von Axios lass Instanz = axios.create(); Instanz.defaults.baseURL = "http://127.0.0.1:8888"; instance.defaults.headers['Inhaltstyp'] = 'multipart/Formulardaten'; instance.defaults.transformRequest = (Daten, Header) => { const contentType = headers['Inhaltstyp']; wenn (contentType === "application/x-www-form-urlencoded") return Qs.stringify(data); Daten zurückgeben; }; Instanz.Interceptors.Response.Verwenden(Antwort => { Antwortdaten zurückgeben; }); Der Dateiupload basiert im Allgemeinen auf zwei Methoden: FormData und Base64 Dateiupload basierend auf FormData//Front-End-Code// Zeigt hauptsächlich den Kerncode zum Hochladen basierend auf ForData upload_button_upload.addEventListener('click', function () { wenn (upload_button_upload.classList.contains('deaktivieren') || upload_button_upload.classList.contains('wird geladen')) return; wenn (!_Datei) { alert('Bitte wählen Sie zuerst die hochzuladende Datei aus~~'); zurückkehren; } ändereDeaktivieren(true); // Übergebe die Datei an den Server: FormData let formData = neue FormData(); //Felder entsprechend den Hintergrundanforderungen hinzufügen formData.append('file', _file); formData.append('Dateiname', _Datei.name); Instanz.post('/upload_single', formData).then(data => { wenn (+data.code === 0) { alert(`Die Datei wurde erfolgreich hochgeladen~~, Sie können basierend auf ${data.servicePath}~~ auf diese Ressource zugreifen`); zurückkehren; } gibt Promise.reject(data.codeText) zurück; }).catch(Grund => { alert('Dateiupload fehlgeschlagen, bitte versuchen Sie es später erneut~~'); }).schließlich(() => { Handle löschen(); ändereDeaktivieren(false); }); }); Dateiupload basierend auf BASE64BASE64-spezifische Methodeexport changeBASE64(Datei) => { gib ein neues Versprechen zurück (Auflösen => { Fügt eine neue Funktion zum Lesen von Dateien hinzu. fileReader.readAsDataURL(Datei); fileReader.onload = ev => { lösen(ev.target.result); }; }); }; Konkrete Umsetzung upload_inp.addEventListener('ändern', asynchrone Funktion () { let Datei = upload_inp.files[0], BASE64, Daten; wenn (!Datei) zurückgeben; if (Dateigröße > 2 * 1024 * 1024) { alert('Die hochgeladene Datei darf nicht größer als 2 MB sein~~'); zurückkehren; } upload_button_select.classList.add('wird geladen'); // Base64 abrufen BASE64 = warte auf changeBASE64(Datei); versuchen { Daten = warte auf Instanz.Post('/upload_single_base64', { // encodeURIComponent (BASE64) verhindert, dass Sonderzeichen während der Übertragung verstümmelt werden. Gleichzeitig muss das Backend decodeURIComponent verwenden, um die Datei zu dekodieren: encodeURIComponent (BASE64), Dateiname: datei.name }, { Überschriften: { „Inhaltstyp“: „Anwendung/x-www-form-urlencoded“ } }); wenn (+data.code === 0) { alert(`Herzlichen Glückwunsch, die Datei wurde erfolgreich hochgeladen. Sie können über die Adresse ${data.servicePath} darauf zugreifen~~`); zurückkehren; } wirf Daten.CodeText; } fangen (Fehler) { alert('Leider ist der Dateiupload fehlgeschlagen. Bitte versuchen Sie es später erneut~~'); Endlich upload_button_select.classList.remove('wird geladen'); } **});** Im obigen Beispiel generiert das Backend einen zufälligen Namen für die vom Frontend empfangene Datei und speichert sie. Einige Unternehmen führen diesen Schritt jedoch im Frontend aus und senden den generierten Namen an das Backend. Als Nächstes implementieren wir diese Funktion. Das Frontend generiert einen Dateinamen und übergibt ihn an das BackendHier müssen Sie das oben erwähnte SparkMD5-Plugin verwenden. Ich werde nicht näher auf die Verwendung eingehen. Bitte lesen Sie die Dokumentation. Kapselt die Methode zum Lesen des Dateistroms const changeBuffer = Datei => { gib ein neues Versprechen zurück (Auflösen => { Fügt eine neue Funktion zum Lesen von Dateien hinzu. fileReader.readAsArrayBuffer(Datei); fileReader.onload = ev => { lass Puffer = ev.target.result, Funke = neuer SparkMD5.ArrayBuffer(), HASCH, Suffix; spark.append(Puffer); // Dateinamen abrufen HASH = spark.end(); // Suffixnamen abrufen suffix = /\.([a-zA-Z0-9]+)$/.exec(file.name)[1]; lösen({ Puffer, HASCH, Suffix, Dateiname: `${HASH}.${suffix}` }); }; }); }; Serverbezogenen Code hochladen upload_button_upload.addEventListener('klicken', asynchrone Funktion () { wenn (checkIsDisable(this)) zurückgeben; wenn (!_Datei) { alert('Bitte wählen Sie zuerst die hochzuladende Datei aus~~'); zurückkehren; } ändereDeaktivieren(true); // Generiere den HASH-Namen der Datei let { Dateiname } = warte auf changeBuffer(_file); let formData = neue FormData(); formData.append('Datei', _Datei); formData.append('Dateiname', Dateiname); Instanz.post('/upload_einzelner_name', formData).then(data => { wenn (+data.code === 0) { alert(`Die Datei wurde erfolgreich hochgeladen~~, Sie können basierend auf ${data.servicePath}~~ auf diese Ressource zugreifen`); zurückkehren; } gibt Promise.reject(data.codeText) zurück; }).catch(Grund => { alert('Dateiupload fehlgeschlagen, bitte versuchen Sie es später erneut~~'); }).schließlich(() => { ändereDeaktivieren(false); upload_abbre.style.display = "keine"; upload_abbre_img.src = ''; _Datei = null; }); }); Upload-FortschrittskontrolleDiese Funktion ist relativ einfach. Die in diesem Artikel verwendete Anforderungsbibliothek ist axios. Die Fortschrittskontrolle wird hauptsächlich basierend auf der von axios bereitgestellten Funktion onUploadProgress implementiert. Schauen wir uns das Implementierungsprinzip dieser Funktion an. Lauschen auf xhr.upload.onprogress Das Objekt, das nach dem Hochladen der Datei erhalten wird Konkrete Umsetzung (Funktion () { let upload = document.querySelector('#upload4'), upload_inp = upload.querySelector('.upload_inp'), upload_button_select = upload.querySelector('.upload_button.select'), upload_progress = upload.querySelector('.upload_progress'), upload_progress_value = upload_progress.querySelector('.value'); // Überprüfen, ob es in einem betriebsfähigen Zustand ist const checkIsDisable = element => { Lassen Sie Klassenliste = Element.Klassenliste; return classList.contains('deaktivieren') || classList.contains('wird geladen'); }; upload_inp.addEventListener('ändern', asynchrone Funktion () { let Datei = upload_inp.files[0], Daten; wenn (!Datei) zurückgeben; upload_button_select.classList.add('wird geladen'); versuchen { let formData = neue FormData(); formData.append('Datei', Datei); formData.append('Dateiname', Dateiname); Daten = warte auf Instanz.Post('/upload_single', formData, { //Rückruffunktion xhr.upload.onprogress beim Dateiupload beimUploadProgress(ev) { lassen { geladen, gesamt } = ev; upload_progress.style.display = "Block"; upload_progress_value.style.width = `${geladen/gesamt*100} %`; } }); wenn (+data.code === 0) { upload_progress_value.style.width = `100%`; alert(`Herzlichen Glückwunsch, die Datei wurde erfolgreich hochgeladen. Sie können über ${data.servicePath}~~ auf die Datei zugreifen`); zurückkehren; } wirf Daten.CodeText; } fangen (Fehler) { alert('Leider ist der Dateiupload fehlgeschlagen. Bitte versuchen Sie es später erneut~~'); Endlich upload_button_select.classList.remove('wird geladen'); upload_progress.style.display = "keine"; upload_progress_value.style.width = `0%`; } }); upload_button_select.addEventListener('klicken', Funktion () { wenn (checkIsDisable(this)) zurückgeben; upload_inp.click(); }); })(); Hochladen großer DateienGroße Dateien werden normalerweise in Slices hochgeladen, was die Geschwindigkeit des Datei-Uploads erhöhen kann. Das Front-End teilt den Dateistrom in Slices und kommuniziert dann zur Übertragung mit dem Back-End. Dies wird normalerweise mit einer Breakpoint-Übertragung kombiniert. Zu diesem Zeitpunkt stellt das Back-End im Allgemeinen drei Schnittstellen bereit. Die erste Schnittstelle erhält die hochgeladenen Slice-Informationen, die zweite Schnittstelle überträgt die Front-End-Slice-Datei und die dritte Schnittstelle weist das Back-End an, die Dateien zusammenzuführen, nachdem alle Slices hochgeladen wurden. Das Slicen kann auf zwei Arten erfolgen: mit fester Zahl und mit fester Größe. Wir kombinieren hier beides. // Implementieren Sie die Datei-Slicing-Verarbeitung „feste Zahl und feste Größe“ sei max = 1024 * 100, Anzahl = Math.ceil(Dateigröße / max), Index = 0, Stücke = []; wenn (Anzahl > 100) { max = Dateigröße / 100; Anzahl = 100; } während (Index < Anzahl) { Stücke.push({ // Die Datei selbst hat eine Slice-Methode, siehe folgende Abbildung Datei: file.slice(index * max, (index + 1) * max), Dateiname: `${HASH}_${index+1}.${suffix}` }); Index++; } An den Server senden chunks.fürJeden(chunk => { let fm = neue Formulardaten; fm.append('Datei', chunk.datei); fm.append('Dateiname', chunk.Dateiname); Instanz.post('/upload_chunk', fm).dann(data => { wenn (+data.code === 0) { vervollständigen(); zurückkehren; } gibt Promise.reject(data.codeText) zurück; }).catch(() => { alert('Der aktuelle Slice-Upload ist fehlgeschlagen. Bitte versuchen Sie es später erneut~~'); klar(); }); }); Datei-Upload + Fortsetzen beim Ausschalten + Fortschrittskontrolle upload_inp.addEventListener('ändern', asynchrone Funktion () { let Datei = upload_inp.files[0]; wenn (!Datei) zurückgeben; upload_button_select.classList.add('wird geladen'); upload_progress.style.display = "Block"; // Den HASH der Datei abrufen lass schon = [], Daten = null, { HASCH, Suffix } = warte auf changeBuffer(Datei); // Informationen zum hochgeladenen Slice abrufen try { Daten = warte auf Instanz.get('/upload_already', { Parameter: { HASCH } }); wenn (+data.code === 0) { bereits = Daten.Dateiliste; } } fangen (Fehler) {} // Implementieren Sie die Datei-Slicing-Verarbeitung „feste Zahl und feste Größe“ sei max = 1024 * 100, Anzahl = Math.ceil(Dateigröße / max), Index = 0, Stücke = []; wenn (Anzahl > 100) { max = Dateigröße / 100; Anzahl = 100; } während (Index < Anzahl) { Stücke.push({ Datei: Datei.Slice(Index * max, (Index + 1) * max), Dateiname: `${HASH}_${index+1}.${suffix}` }); Index++; } // Upload-Verarbeitung erfolgreich. Index = 0; const löschen = () => { upload_button_select.classList.remove('wird geladen'); upload_progress.style.display = "keine"; upload_progress_value.style.width = "0%"; }; const complate = async () => { //Fortschrittsbalken steuern index++; upload_progress_value.style.width = `${index/count*100}%`; // Wenn alle Slices erfolgreich hochgeladen wurden, führen wir die Slices zusammen, if (index < count) return; upload_progress_value.style.width = `100%`; versuchen { Daten = warte auf Instanz.Post('/upload_merge', { HASCH, zählen }, { Überschriften: { „Inhaltstyp“: „Anwendung/x-www-form-urlencoded“ } }); wenn (+data.code === 0) { alert(`Herzlichen Glückwunsch, die Datei wurde erfolgreich hochgeladen. Sie können über ${data.servicePath}~~ auf die Datei zugreifen`); klar(); zurückkehren; } wirf Daten.CodeText; } fangen (Fehler) { alert('Das Zusammenführen der Slices ist fehlgeschlagen. Bitte versuchen Sie es später erneut~~'); klar(); } }; // Lade jedes Slice auf den Server hoch chunks.forEach(chunk => { // Bereits hochgeladen, kein erneutes Hochladen nötig if (already.length > 0 && already.includes(chunk.filename)) { vervollständigen(); zurückkehren; } let fm = neue Formulardaten; fm.append('Datei', chunk.datei); fm.append('Dateiname', chunk.Dateiname); Instanz.post('/upload_chunk', fm).dann(data => { wenn (+data.code === 0) { vervollständigen(); zurückkehren; } gibt Promise.reject(data.codeText) zurück; }).catch(() => { alert('Der aktuelle Slice-Upload ist fehlgeschlagen. Bitte versuchen Sie es später erneut~~'); klar(); }); }); }); Servercode (Hochladen großer Dateien + Wiederaufnahme von Haltepunkten)// Große Dateisegmente hochladen und Segmente zusammenführen const merge = function merge(HASH, count) { returniere neues Promise(async (auflösen, ablehnen) => { let path = `${uploadDir}/${HASH}`, Dateiliste = [], Suffix, istExistiert; isExists = warte auf existiere(Pfad); wenn (!istExistiert) { reject('HASH-Pfad nicht gefunden!'); zurückkehren; } fileList = fs.readdirSync(Pfad); if (Dateiliste.Länge < Anzahl) { reject('der Slice wurde nicht hochgeladen!'); zurückkehren; } Dateiliste.sortieren((a, b) => { sei reg = /_(\d+)/; return reg.exec(a)[1] - reg.exec(b)[1]; }).fürJedes(Element => { !Suffix ? Suffix = /\.([0-9a-zA-Z]+)$/.exec(item)[1] : null; fs.appendFileSync(`${uploadDir}/${HASH}.${suffix}`, fs.readFileSync(`${path}/${item}`)); fs.unlinkSync(`${path}/${item}`); }); fs.rmdirSync(Pfad); lösen({ Pfad: `${uploadDir}/${HASH}.${suffix}`, Dateiname: `${HASH}.${suffix}` }); }); }; app.post('/upload_chunk', async (req, res) => { versuchen { lassen { Felder, Dateien } = warte auf multiparty_upload(req); let file = (Dateien.Datei && Dateien.Datei[0]) || {}, Dateiname = (Felder.Dateiname && Felder.Dateiname[0]) || "", Pfad = '', istExistiert = falsch; // Erstellen Sie ein temporäres Verzeichnis zum Speichern von Slices let [, HASH] = /^([^_]+)_(\d+)/.exec(filename); Pfad = `${uploadDir}/${HASH}`; !fs.existsSync(Pfad) ? fs.mkdirSync(Pfad) : null; // Speichern Sie den Slice in einem temporären Verzeichnispfad = `${uploadDir}/${HASH}/${filename}`; isExists = warte auf existiere(Pfad); wenn (istExistiert) { res.send({ Code: 0, CodeText: 'Datei existiert', originalFilename: Dateiname, servicePath: Pfad.ersetzen(__dirname, HOSTNAME) }); zurückkehren; } writeFile(res, Pfad, Datei, Dateiname, true); } fangen (Fehler) { res.send({ Code: 1, CodeText: Fehler }); } }); app.post('/upload_merge', async (req, res) => { lassen { HASCH, zählen } = erforderlich.body; versuchen { lassen { Dateiname, Weg } = warte auf Zusammenführung (HASH, Anzahl); res.send({ Code: 0, CodeText: „Zusammenführung erfolgreich“, originalFilename: Dateiname, servicePath: Pfad.ersetzen(__dirname, HOSTNAME) }); } fangen (Fehler) { res.send({ Code: 1, CodeText: Fehler }); } }); app.get('/upload_already', async (req, res) => { lassen { HASCH } = Anforderungsabfrage; let path = `${uploadDir}/${HASH}`, Dateiliste = []; versuchen { fileList = fs.readdirSync(Pfad); Dateiliste = Dateiliste.sort((a, b) => { sei reg = /_(\d+)/; return reg.exec(a)[1] - reg.exec(b)[1]; }); res.send({ Code: 0, Codetext: '', Dateiliste: Dateiliste }); } fangen (Fehler) { res.send({ Code: 0, CodeText: '', Dateiliste: Dateiliste }); } }); ZusammenfassenDies ist das Ende dieses Artikels zum Verwalten großer Datei-Uploads und zum Fortsetzen von Haltepunkten basierend auf js. Weitere relevante Inhalte zu großen Datei-Uploads und zum Fortsetzen von Haltepunkten finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:
|
<<: MySQL-Lernnotizen zum Umgang mit doppelten Daten
>>: Zusammenfassung der Methoden zum Abfragen von MySQL-Benutzerberechtigungen
Problembeschreibung Ich möchte CSS verwenden, um ...
Beispielverwendung Code kopieren Der Code lautet w...
Die Wirkung ist ganz einfach: Kopieren Sie einfach...
Dieser Artikel erläutert anhand von Beispielen di...
Inhaltsverzeichnis 1. Einleitung 2. auswählen 2.1...
Closure-Implementierung privater Variablen Privat...
Bereits zu Kernel 2.6-Zeiten wurde ein neues Sich...
Sie können das Desktopsystem von der offiziellen ...
Wenn Sie zur Implementierung eines Kontrollkästch...
Was ist WSL Zitat aus der Baidu-Enzyklopädie: Das...
Ich habe vor Kurzem meine persönliche Website neu...
Inhaltsverzeichnis 1. Synchrones AJAX 2. Asynchro...
Inhaltsverzeichnis Zufallszahlen generieren Gener...
Auf alle Orchestrierungsdateien und Konfiguration...
Beim Verwenden des XAML-Layouts müssen manchmal ei...