So verwalten Sie große Datei-Uploads und Breakpoint-Resumes basierend auf js

So verwalten Sie große Datei-Uploads und Breakpoint-Resumes basierend auf js

Vorwort

Das 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-Struktur

Seitenanzeige

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 BASE64

BASE64-spezifische Methode

export 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 Backend

Hier 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-Fortschrittskontrolle

Diese 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 Dateien

Groß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
            });
        }
    });

Zusammenfassen

Dies 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:
  • JavaScript mit Ckeditor + Ckfinder - detaillierte Erläuterung zum Hochladen von Dateien
  • Node.js verwendet die Express-Fileupload-Middleware zum Hochladen von Dateien
  • jQuery implementiert asynchronen Dateiupload ajaxfileupload.js
  • Backend-Codebeispiel für den Upload großer Dateien basierend auf JavaScript
  • JS kann den Datei-Upload mit Unterbrechungspunkten fortsetzen, um eine Code-Analyse zu erreichen
  • Die FormData-Klasse in JS implementiert den Dateiupload
  • Die FileReader-Klasse in JS implementiert die Funktion der zeitnahen Vorschau des Datei-Uploads
  • js zum Implementieren von Details im Datei-Upload-Stil

<<:  MySQL-Lernnotizen zum Umgang mit doppelten Daten

>>:  Zusammenfassung der Methoden zum Abfragen von MySQL-Benutzerberechtigungen

Artikel empfehlen

Beispiele für die Verwendung von HTML-Metadaten

Beispielverwendung Code kopieren Der Code lautet w...

Beispiel für automatischen Stoppeffekt nach Text-Scrollen

Die Wirkung ist ganz einfach: Kopieren Sie einfach...

Detaillierte Erläuterung der Nginx-Strombegrenzungskonfiguration

Dieser Artikel erläutert anhand von Beispielen di...

Verwendung von „Select“, „Distinct“ und „Limit“ in MySQL

Inhaltsverzeichnis 1. Einleitung 2. auswählen 2.1...

Erste Schritte mit SELinux

Bereits zu Kernel 2.6-Zeiten wurde ein neues Sich...

So installieren Sie den Vim-Editor unter Linux (Ubuntu 18.04)

Sie können das Desktopsystem von der offiziellen ...

So installieren und konfigurieren Sie WSL unter Windows

Was ist WSL Zitat aus der Baidu-Enzyklopädie: Das...

So verfolgen Sie Benutzer mit JS

Inhaltsverzeichnis 1. Synchrones AJAX 2. Asynchro...

So verwenden Sie Docker-Compose zum Erstellen eines ELK-Clusters

Auf alle Orchestrierungsdateien und Konfiguration...

So zeichnen Sie eine Schaltfläche in XAML als Kreis neu

Beim Verwenden des XAML-Layouts müssen manchmal ei...