JavaScript implementiert die Verarbeitung großer Datei-Uploads

JavaScript implementiert die Verarbeitung großer Datei-Uploads

Beim Hochladen von Dateien, z. B. Videodateien, die nur einige zehn MB oder über 1 GB groß sind, treten beim Senden von Daten mit der normalen HTTP-Anforderungsmethode häufig die folgenden Probleme auf:

1. Die Datei ist zu groß und überschreitet die Anforderungsgrößenbeschränkung des Servers.
2. Die Anforderungszeit ist zu lang und die Anforderung läuft ab.
3. Die Übertragung wird unterbrochen und muss erneut hochgeladen werden, wodurch alle bisherigen Bemühungen umsonst waren.

Diese Probleme beeinträchtigen die Benutzererfahrung erheblich. Daher wird im Folgenden eine Lösung für die Dateisegmentierung und den Upload auf Basis von nativem JavaScript vorgestellt. Der konkrete Implementierungsprozess ist wie folgt:

1. Holen Sie sich das Dateiobjekt über DOM, führen Sie eine MD5-Verschlüsselung für die Datei durch (Dateiinhalt + Dateititelformat) und verwenden Sie SparkMD5, um die Datei zu verschlüsseln.
2. Richten Sie Sharding ein. File basiert auf Blob und erbt die Funktionen von Blob. Sie können File als Unterklasse von Blob betrachten, was für die Slice-Methode von Blob praktisch ist, um File-Sharding durchzuführen und sie nacheinander hochzuladen.
3. Nachdem die Fragmentdateien hochgeladen wurden, fordern Sie das Merge-Interface-Backend auf, die Dateien zusammenzuführen.

1. Datei hochladen Seite

<!DOCTYPE html>
<html lang="de">

<Kopf>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=Gerätebreite, Anfangsmaßstab=1.0">
  <meta http-equiv="X-UA-kompatibel" content="ie=edge">
  <title>Datei-Upload</title>
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>
  <script src="https://code.jquery.com/jquery-3.4.1.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/spark-md5/3.0.0/spark-md5.js"></script>
  <Stil>
    /* Benutzerdefinierter Fortschrittsbalkenstil */
    .precent Eingabe[Typ=Bereich] {
      -webkit-auftritt: keines;
      /*Standardstil des Systems löschen*/
      Breite: 7,8rem;
      /* Hintergrund: -webkit-linear-gradient(#ddd, #ddd) keine Wiederholung, #ddd; */
      /*Setze die linke Farbe auf #61bd12 und die rechte Farbe auf #ddd*/
      Hintergrundgröße: 75 % 100 %;
      /*Linkes und rechtes Breitenverhältnis festlegen*/
      Höhe: 0,6rem;
      /*Höhe des Balkens*/
      Randradius: 0,4rem;
      Rand: 1px durchgezogen #ddd;
      Box-Schatten: 0 0 10px rgba(0,0,0,.125) Einschub;
    }

    /*Blockstil ziehen*/
    .precent Eingabe [Typ=Bereich]::-webkit-slider-thumb {
      -webkit-auftritt: keines;
      /*Standardstil des Systems löschen*/
      Höhe: .9rem;
      /*Blockhöhe ziehen*/
      Breite: .9rem;
      /*Blockbreite ziehen*/
      Hintergrund: #fff;
      /*Blockhintergrund ziehen*/
      Randradius: 50 %;
      /*Stellen Sie das Erscheinungsbild auf rund ein*/
      Rand: durchgezogen 1px #ddd;
      /*Rahmen festlegen*/
    }

  </Stil>
</Kopf>

<Text>
  <h1>Test zum Hochladen großer Dateien in mehreren Teilen</h1>
  <div>
    <input id="Datei" Typ="Datei" Name="Avatar" />
    <div Stil="Padding: 10px 0;">
      <input id="submitBtn" type="button" value="Senden" />
      <input id="pauseBtn" type="button" value="Pause" />
    </div>
    <div Klasse="vorläufig">
      <Eingabetyp="Bereich" Wert="0" /><span id="precentVal">0 %</span>
    </div>
  </div>
  <script type="text/javascript" src="./js/index.js"></script>
</body>

</html>

2. Große Dateien in Stücken hochladen

$(Dokument).bereit(() => {
  const submitBtn = $('#submitBtn'); //Senden-Schaltfläche const precentDom = $(".precent input")[0]; //Fortschrittsbalken const precentVal = $("#precentVal"); //Fortschrittsbalkenwert entspricht dom
  const pauseBtn = $('#pauseBtn'); // Pause-Taste // Die Größe jedes Blocks ist auf 1 Megabyte eingestellt const chunkSize = 1 * 1024 * 1024;
  // Holen Sie sich die Slice-Methode und machen Sie sie kompatibel const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
  // MD5-Verschlüsselung der Datei (Dateiinhalt + Dateititelformat)
  const hashFile = (Datei) => {
    returniere neues Promise((lösen, ablehnen) => {
      const chunks = Math.ceil(Dateigröße / Chunkgröße);
      lass currentChunk = 0;
      const spark = neuer SparkMD5.ArrayBuffer();
      const fileReader = neuer FileReader();
      Funktion loadNext() {
        const start = aktueller Chunk * Chunkgröße;
        const end = start + chunkSize >= Dateigröße? Dateigröße: start + chunkSize;
        fileReader.readAsArrayBuffer(blobSlice.call(Datei, Start, Ende));
      }
      fileReader.onload = e => {
        spark.append(e.target.result); // Array-Puffer anhängen
        aktuellerChunk += 1;
        wenn (aktuellerChunk < chunks) {
          ladenWeiter();
        } anders {
          console.log('Laden abgeschlossen');
          const Ergebnis = Spark.Ende();
          // MD5-Verschlüsselung nach Inhalt und Dateiname const sparkMd5 = new SparkMD5();
          sparkMd5.append(Ergebnis);
          sparkMd5.append(Datei.Name);
          const hexHash = sparkMd5.end();
          auflösen(hexHash);
        }
      };
      fileReader.onerror = () => {
        console.warnen('Das Lesen der Datei ist fehlgeschlagen!');
      };
      ladenWeiter();
    }).catch(err => {
      console.log(fehler);
    });
  }

  // Senden submitBtn.on('click', async () => {
    var pauseStatus = false;
    var nowUploadNums = 0
    // 1. Datei lesen const fileDom = $('#file')[0];
    const-Dateien = fileDom.files;
    const Datei = Dateien[0];
    wenn (!Datei) {
      alert('Keine Datei erhalten');
      zurückkehren;
    }
    // 2. Setze die Sharding-Parameterattribute und hole den MD5-Wert der Datei const hash = await hashFile(file); //Datei-Hash 
    const blockCount = Math.ceil(file.size / chunkSize); // Gesamtzahl der Shards const axiosPromiseArray = []; // axiosPromise-Array // Datei-Upload const uploadFile = () => {
      const start = jetztUploadNums * chunkSize;
      const end = Math.min(Dateigröße, Start + Blockgröße);
      // Formular erstellen const form = new FormData();
      // Die Methode blobSlice.call(file, start, end) wird zum Datei-Slicing verwendet form.append('file', blobSlice.call(file, start, end));
      form.append('index', jetztUploadNums);
      form.append('hash', hash);
      // Ajax übermittelt Fragmente und der Inhaltstyp ist multipart/form-data
      const axiosOptions = {
        beimUploadProgress: e => {
          jetztUploadNums++;
          // Bestimmen Sie, ob der Upload des Fragments abgeschlossen ist, wenn (nowUploadNums < blockCount) {
            setPrecent(jetztUploadNums, Blockanzahl);
            UploadFile(jetztUploadNums)
          } anders {
            // 4. Nachdem alle Shards hochgeladen wurden, fordern Sie die Zusammenführung der Shard-Dateien an axios.all(axiosPromiseArray).then(() => {
              setPrecent(blockCount, blockCount); // Alle Uploads abgeschlossen axios.post('/file/merge_chunks', {
                Name: Dateiname,
                gesamt: blockCount,
                Hash
              }).dann(res => {
                console.log(res.data, Datei);
                pauseStatus = falsch;
                alert('Hochladen erfolgreich');
              }).catch(err => {
                console.log(fehler);
              });
            });
          }
        },
      };
      // Zum Promise-Array hinzufügen if (!pauseStatus) {
        axiosPromiseArray.push(axios.post('/Datei/Hochladen', Formular, axiosOptions));
      }

    }
    //Setze die Fortschrittsbalkenfunktion setPrecent(now, total) {
      var prencentValue = ((jetzt / gesamt) * 100).toFixed(2)
      precentDom.value = precentWert
      precentVal.text(precentValue + '%')
      precentDom.style.cssText = `Hintergrund:-webkit-linear-gradient(oben, #059CFA, #059CFA) 0 % 0 % / ${prencentValue} % 100 % keine Wiederholung`
    }
    // Pause pauseBtn.on('click', (e) => {
      pauseStatus = !pauseStatus;
      e.currentTarget.value = pauseStatus ? 'Start' : 'Pause'
      if (!pauseStatus) {
        UploadFile(jetztUploadNums)
      }
    })
    Datei hochladen();
  });
})

3. Datei-Upload und Zusammenführen der Shard-Dateischnittstelle (Knoten)

const Router = erforderlich('koa-router');
const multer = require('koa-multer');
const fs = erfordern('fs-extra');
const path = require('Pfad');
const router = neuer Router();

const { mkdirsSync } = require('../utils/dir');
const uploadPath = path.join(__dirname, 'upload');
const chunkUploadPath = Pfad.join(uploadPath, 'temp');
const upload = multer({ dest: chunkUploadPath });

// Schnittstelle zum Hochladen von Dateien router.post('/file/upload', upload.single('file'), async (ctx, next) => {
  const { index, hash } = ctx.req.body;
  const chunksPath = path.join(chunkUploadPath, hash, '/');
  if(!fs.existsSync(chunksPath)) mkdirsSync(chunksPath);
  fs.renameSync(ctx.req.file.path, chunksPath + hash + '-' + index);
  ctx.status = 200;
  ctx.res.end('Erfolgreich');
}) 
// Fragmentdateischnittstelle zusammenführen router.post('/file/merge_chunks', async (ctx, next) => {
  const { Name, Gesamt, Hash } = ctx.request.body;
  const chunksPath = path.join(chunkUploadPath, hash, '/');
  const filePath = Pfad.Join(UploadPath, Name);
  // Alle Chunks lesen
  const chunks = fs.readdirSync(chunksPath);
  // Speicherdatei erstellen fs.writeFileSync(filePath, ''); 
  wenn (chunks.length !== gesamt || chunks.length === 0) {
    ctx.status = 200;
    ctx.res.end('Die Anzahl der Slice-Dateien stimmt nicht überein');
    zurückkehren;
  }
  für (sei i = 0; i < gesamt; i++) {
    // An die Datei anhängen fs.appendFileSync(filePath, fs.readFileSync(chunksPath + hash + '-' +i));
    // Lösche den diesmal verwendeten Block    
    fs.unlinkSync(chunksPath + hash + '-' +i);
  }
  fs.rmdirSync(chunksPath);
  // Die Dateien wurden erfolgreich zusammengeführt und die Dateiinformationen können in der Datenbank gespeichert werden.
  ctx.status = 200;
  ctx.res.end('Erfolgreich');
})

Das Obige ist der grundlegende Prozess des Hochladens von Dateien in Teilen. Der Upload-Fortschrittsbalken sowie die Vorgänge „Pause“ und „Hochladen starten“ werden während des Prozesses hinzugefügt. Siehe den detaillierten Code

Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, er wird für jedermanns Studium hilfreich sein. Ich hoffe auch, dass jeder 123WORDPRESS.COM unterstützen wird.

Das könnte Sie auch interessieren:
  • Beispiel für die Konvertierung von JavaScript-Datentypen (Konvertieren anderer Typen in Zeichenfolgen, numerische Typen und Boolesche Typen)
  • Beispiel für die Konvertierung eines flachen JavaScript-Arrays in eine Baumstruktur
  • Javascript implementiert die Webversion des Flipperspiels
  • JavaScript zur Implementierung der Webversion des Schlangenspiels
  • Ein Artikel zur Einführung in Java Script

<<:  Beim Einrichten von Jenkins in einer Docker-Umgebung werden im Konsolenprotokoll beim Erstellen von Aufgaben verstümmelte chinesische Zeichen angezeigt

>>:  So vergleichen Sie zwei Datenbanktabellenstrukturen in MySQL

Artikel empfehlen

503 Dienst nicht verfügbar Fehlerlösungserklärung

1. Beim Öffnen der Webseite wird die Meldung „503...

Ein kurzer Vortrag über den Diff-Algorithmus in Vue

Inhaltsverzeichnis Überblick Virtueller Dom Prinz...

Detaillierte Einführung in die gespeicherten MySQL-Funktionen

Inhaltsverzeichnis 1. Erstellen Sie eine gespeich...

So zeigen Sie alle laufenden Prozesse in Linux an

Sie können den Befehl ps verwenden. Es kann relev...

Beschreiben Sie kurz die vier Transaktionsisolationsebenen von MySql

Isolationsstufe: Isolation ist komplizierter als ...

js zur Realisierung von Login- und Registrierungsfunktionen

In diesem Artikelbeispiel wird der spezifische Co...

Schnelles Verständnis des Vue-Routing-Navigationsschutzes

Inhaltsverzeichnis 1. Globale Wache 1. Globale Fr...

Lernen Sie MySQL auf einfache Weise

Vorwort Die Datenbank war schon immer meine Schwa...

Die große Rolle von HTML-Meta

Es gibt zwei Metaattribute: Name und http-equiv. D...

Ein einfaches Beispiel für die Verwendung von Vue3-Routing VueRouter4

Routenplanung vue-router4 behält den Großteil der...

So importieren Sie CSS-Stile in externe HTML-Stylesheets

Der Link-In-Stil besteht darin, alle Stile in ein...

So verwenden Sie benutzerdefinierte CSS-Variablen in Vue

Inhaltsverzeichnis Die benutzerdefinierte CSS-Var...