JavaScript は大容量ファイルのアップロード処理を実装します

JavaScript は大容量ファイルのアップロード処理を実装します

数十 MB 程度の小さいものから 1G 以上の大きいものまで、ビデオ ファイルなどのファイルのアップロードを処理する場合、通常の HTTP リクエスト メソッドを使用してデータを送信すると、次のような問題が発生することがよくあります。

1. ファイルが大きすぎて、サーバーの要求サイズ制限を超えています。
2. リクエスト時間が長すぎてリクエストがタイムアウトになる。
3. 送信が中断され、再アップロードする必要があり、これまでの努力がすべて無駄になります。

これらの問題はユーザーエクスペリエンスに大きな影響を与えるため、以下ではネイティブ JavaScript に基づくファイルの分割とアップロードのソリューションを紹介します。具体的な実装プロセスは次のとおりです。

1. DOM を通じてファイル オブジェクトを取得し、ファイル (ファイル コンテンツ + ファイル タイトル形式) に対して MD5 暗号化を実行し、SparkMD5 を使用してファイルを暗号化します。
2. シャーディングを設定します。File は Blob に基づいており、Blob の機能を継承しています。File を Blob のサブクラスと見なすと、Blob のスライス メソッドでファイルのシャーディングを実行し、順番にアップロードするのに便利です。
3. フラグメント ファイルがアップロードされたら、マージ インターフェイス バックエンドにファイルをマージするように要求します。

1. ファイルのアップロードページ

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

<ヘッド>
  <メタ文字セット="UTF-8">
  <meta name="viewport" content="width=デバイス幅、初期スケール=1.0">
  <meta http-equiv="X-UA-compatible" content="ie=edge">
  <title>ファイルのアップロード</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>
  <スタイル>
    /* カスタムプログレスバースタイル */
    .precent 入力[type=range] {
      -webkit-appearance: なし;
      /*システムのデフォルトスタイルをクリア*/
      幅:7.8rem;
      /* 背景: -webkit-linear-gradient(#ddd, #ddd) no-repeat, #ddd; */
      /*左の色を#61bd12、右の色を#dddに設定します*/
      背景サイズ: 75% 100%;
      /*左右の幅の比率を設定する*/
      高さ: 0.6rem;
      /*バーの高さ*/
      境界線の半径: 0.4rem;
      境界線: 1px 実線 #ddd;
      ボックスシャドウ: 0 0 10px rgba(0,0,0,.125) インセット;
    }

    /*ドラッグブロックスタイル*/
    .precent 入力[type=range]::-webkit-slider-thumb {
      -webkit-appearance: なし;
      /*システムのデフォルトスタイルをクリア*/
      高さ: .9rem;
      /*ブロックの高さをドラッグ*/
      幅: .9rem;
      /*ブロック幅をドラッグ*/
      背景: #fff;
      /*ブロックの背景をドラッグ*/
      境界線の半径: 50%;
      /*外観を丸く設定する*/
      境界線: 実線 1px #ddd;
      /*境界線を設定する*/
    }

  </スタイル>
</head>

<本文>
  <h1>大きなファイルのマルチパートアップロードテスト</h1>
  <div>
    <input id="ファイル" type="ファイル" name="アバター" />
    <div style="padding: 10px 0;">
      <input id="submitBtn" type="button" value="送信" />
      <input id="pauseBtn" type="button" value="一時停止" />
    </div>
    <div class="precent">
      <input type="range" value="0" /><span id="precentVal">0%</span>
    </div>
  </div>
  <script type="text/javascript" src="./js/index.js"></script>
</本文>

</html>

2. 大きなファイルを分割してアップロードする

$(ドキュメント).ready(() => {
  const submitBtn = $('#submitBtn'); //送信ボタン const precentDom = $(".precent input")[0]; //進捗バー const precentVal = $("#precentVal"); //進捗バーの値はdomに対応します
  const pauseBtn = $('#pauseBtn'); // 一時停止ボタン // 各チャンクのサイズは 1 メガバイトに設定されています const chunkSize = 1 * 1024 * 1024;
  // スライス メソッドを取得して互換性を持たせます const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
  // ファイルを MD5 で暗号化します (ファイルの内容 + ファイル タイトルの形式)
  const hashFile = (ファイル) => {
    新しい Promise を返します ((resolve, reject) => {
      const chunks = Math.ceil(file.size / chunkSize);
      現在のチャンクを 0 にします。
      定数 spark = 新しい SparkMD5.ArrayBuffer();
      新しいFileReader()を作成します。
      関数loadNext() {
        const start = currentChunk * chunkSize;
        const end = start + chunkSize >= file.size ? file.size : start + chunkSize;
        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
      }
      ファイルリーダー.onload = e => {
        spark.append(e.target.result); // 配列バッファを追加する
        現在のチャンク += 1;
        (現在のチャンク < チャンク) の場合 {
          ロードNext();
        } それ以外 {
          console.log('読み込みが完了しました');
          定数結果 = spark.end();
          // コンテンツとファイル名による MD5 暗号化 const sparkMd5 = new SparkMD5();
          sparkMd5.append(結果);
          sparkMd5.append(ファイル名);
          定数 hexHash = sparkMd5.end();
          16進ハッシュを解決します。
        }
      };
      ファイルリーダー.onerror = () => {
        console.warn('ファイルの読み取りに失敗しました!');
      };
      ロードNext();
    }).catch(エラー => {
      コンソールログ(エラー);
    });
  }

  // 送信 submitBtn.on('click', async () => {
    var pauseStatus = false;
    var nowUploadNums = 0
    // 1. ファイルを読み取る const fileDom = $('#file')[0];
    const ファイル = fileDom.files;
    定数ファイル = files[0];
    if (!ファイル) {
      alert('ファイルが取得されませんでした');
      戻る;
    }
    // 2. シャーディングパラメータ属性を設定し、ファイルのMD5値を取得します。const hash = await hashFile(file); //ファイルハッシュ 
    const blockCount = Math.ceil(file.size / chunkSize); // シャードの総数 const axiosPromiseArray = []; // axiosPromise 配列 // ファイルのアップロード const uploadFile = () => {
      const start = nowUploadNums * chunkSize;
      const end = Math.min(file.size, start + chunkSize);
      // フォームを構築します const form = new FormData();
      // blobSlice.call(file, start, end) メソッドは、ファイル スライスを実行するために使用されます。form.append('file', blobSlice.call(file, start, end));
      フォームに追加します('index', nowUploadNums);
      form.append('ハッシュ', ハッシュ);
      // Ajax はフラグメントを送信し、コンテンツ タイプは multipart/form-data です
      定数 axiosOptions = {
        アップロードの進行状況: e => {
          今アップロードした数値++;
          // フラグメントのアップロードが完了したかどうかを判定します if (nowUploadNums < blockCount) {
            setPrecent(nowUploadNums、ブロック数);
            アップロードファイル(現在のアップロード数)
          } それ以外 {
            // 4. すべてのシャードがアップロードされたら、シャードファイルのマージをリクエストします。axios.all(axiosPromiseArray).then(() => {
              setPrecent(blockCount, blockCount); // すべてのアップロードが完了しました axios.post('/file/merge_chunks', {
                名前: ファイル名、
                合計: ブロック数、
                ハッシュ
              }).then(res => {
                console.log(res.data、ファイル);
                一時停止ステータス = false;
                alert('アップロードに成功しました');
              }).catch(エラー => {
                コンソールログ(エラー);
              });
            });
          }
        },
      };
      // Promise配列に追加 if (!pauseStatus) {
        axiosPromiseArray.push(axios.post('/file/upload', フォーム, axiosOptions));
      }

    }
    //プログレスバーを設定する function setPrecent(now, total) {
      var prencentValue = ((現在 / 合計) * 100).toFixed(2)
      precentDom.value = prencentValue
      precentVal.text(prencentValue + '%')
      precentDom.style.cssText = `background:-webkit-linear-gradient(top, #059CFA, #059CFA) 0% 0% / ${prencentValue}% 100% 繰り返しなし`
    }
    // 一時停止 pauseBtn.on('click', (e) => {
      一時停止ステータス = !一時停止ステータス;
      e.currentTarget.value = pauseStatus ? '開始' : '一時停止'
      一時停止ステータスの場合
        アップロードファイル(現在のアップロード数)
      }
    })
    ファイルをアップロードします。
  });
})

3. ファイルのアップロードとマージシャードファイルインターフェース(ノード)

const Router = require('koa-router');
const multer = require('koa-multer');
定数 fs = require('fs-extra');
定数パス = require('path');
定数ルーター = 新しいルーター();

const { mkdirsSync } = require('../utils/dir');
const uploadPath = path.join(__dirname, 'upload');
const chunkUploadPath = path.join(uploadPath, 'temp');
const アップロード = multer({ dest: chunkUploadPath });

// ファイルアップロードインターフェース router.post('/file/upload', upload.single('file'), async (ctx, next) => {
  const { インデックス、ハッシュ } = ctx.req.body;
  const chunksPath = path.join(chunkUploadPath, ハッシュ, '/');
  fs.existsSync(chunksPath) が存在する場合、mkdirsSync(chunksPath);
  fs.renameSync(ctx.req.file.path, chunksPath + ハッシュ + '-' + インデックス);
  ctx.ステータス = 200;
  ctx.res.end('成功');
}) 
// フラグメントファイルをマージする interface router.post('/file/merge_chunks', async (ctx, next) => {
  const { 名前、合計、ハッシュ } = ctx.request.body;
  const chunksPath = path.join(chunkUploadPath, ハッシュ, '/');
  const filePath = path.join(アップロードパス、名前);
  // すべてのチャンクを読み込む
  定数チャンク = fs.readdirSync(chunksPath);
  // ストレージファイルを作成します fs.writeFileSync(filePath, ''); 
  チャンクの長さが合計より短い場合、チャンクの長さは 0 になります。
    ctx.ステータス = 200;
    ctx.res.end('スライスファイルの数が一致しません');
    戻る;
  }
  (i = 0 とします; i < 合計; i++) {
    // ファイルに追加します fs.appendFileSync(filePath, fs.readFileSync(chunksPath + hash + '-' +i));
    // 今回使用したチャンクを削除する    
    fs.unlinkSync(チャンクパス + ハッシュ + '-' +i);
  }
  fs.rmdirSync(チャンクパス);
  // ファイルは正常にマージされ、ファイル情報はデータベースに保存できます。
  ctx.ステータス = 200;
  ctx.res.end('成功');
})

上記は、ファイルを分割してアップロードする基本的なプロセスです。アップロードの進行状況バー、一時停止、アップロード開始の操作は、プロセス中に追加されます。詳細なコードを参照してください。

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • JavaScript データ型変換の例 (他の型を文字列、数値型、ブール型に変換する)
  • JavaScript のフラット配列をツリー構造に変換する例
  • JavaScript でピンボール ゲームの Web バージョンを実装する
  • スネークゲームのウェブ版を実装するためのJavaScript
  • Java Script を紹介する記事

<<:  Docker環境でJenkinsを設定すると、タスクをビルドするときにコンソールログに文字化けした中国語の文字が表示されます

>>:  MySQL で 2 つのデータベース テーブル構造を比較する方法

推薦する

Mysql WorkBench のインストールと設定のグラフィックチュートリアル

この記事では、Mysql WorkBenchのインストールと設定のグラフィックチュートリアルを参考ま...

MySQL フラッシュリストとダーティページフラッシュメカニズム

1. レビューMySQL の起動後にバッファ プールが初期化されます。バッファ プールは N 個の空...

Elementはスクリプトを使用して新しいコンポーネントを自動的に構築します

目次背景element-ui の自動構築はどのように機能しますか?メイクファイル新しい.jsファイル...

MySqlのインストールとログインの詳細な説明

LinuxにMySQLがすでにインストールされているかどうかを確認する sudo service m...

MySQL 8.0.16 Win10 zip バージョンのインストールと設定のグラフィック チュートリアル

この記事では、MySQL 8.0.16 Win10 zip版のインストールと設定のグラフィックチュー...

Vue は Tencent TIM インスタント メッセージングを統合します

この記事では主に、Tencent TIM インスタント メッセージングを Vue と統合する方法を紹...

mysql5.7 の新しい json フィールド タイプの使用例の分析

この記事では、MySQL 5.7 で追加された json フィールド タイプの使用方法を例を使って説...

Docker を使用して nginx で tomcat クラスターを構築する方法 (画像とテキスト付き)

まず、Tomcatフォルダを作成します。Dockerの設定を容易にするために、ルートディレクトリに直...

JavaScript で Priority Queue を実装する

目次1. 優先キューの紹介2. 優先キューのカプセル化1. 優先キューの紹介通常のキューに要素が挿入...

mysql8.0.18 で winx64 をインストールするための詳細なチュートリアル (画像とテキスト付き)

MySQLデータベースをダウンロードするには、https://dev.mysql.com/down...

Linux ファイアウォールの状態確認方法の例

Linuxファイアウォールの状態を確認する方法1. 基本操作 # ファイアウォールのステータスを表示...

MySQL サービスに iptables ファイアウォール ポリシーを追加するためのソリューション

MySQL データベースが Centos7 システムにインストールされており、オペレーティング シス...

Ant Design Blazor コンポーネントライブラリのルーティング再利用マルチタブ機能

最近、Ant Design Blazor コンポーネント ライブラリにマルチタブ コンポーネントを実...

MySQLマスタースレーブデータベース構築方法の詳細な説明

この記事では、MySQL マスター/スレーブ データベースの構築方法について説明します。ご参考までに...

vsftpd ユーザーが ssh 経由でログインすることを禁止する方法

序文vsftp は使いやすく安全な FTP サーバー ソフトウェアです。システムユーザーまたは仮想ユ...