数十 MB 程度の小さいものから 1G 以上の大きいものまで、ビデオ ファイルなどのファイルのアップロードを処理する場合、通常の HTTP リクエスト メソッドを使用してデータを送信すると、次のような問題が発生することがよくあります。 1. ファイルが大きすぎて、サーバーの要求サイズ制限を超えています。 これらの問題はユーザーエクスペリエンスに大きな影響を与えるため、以下ではネイティブ JavaScript に基づくファイルの分割とアップロードのソリューションを紹介します。具体的な実装プロセスは次のとおりです。 1. DOM を通じてファイル オブジェクトを取得し、ファイル (ファイル コンテンツ + ファイル タイトル形式) に対して MD5 暗号化を実行し、SparkMD5 を使用してファイルを暗号化します。 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 を応援していただければ幸いです。 以下もご興味があるかもしれません:
|
<<: Docker環境でJenkinsを設定すると、タスクをビルドするときにコンソールログに文字化けした中国語の文字が表示されます
>>: MySQL で 2 つのデータベース テーブル構造を比較する方法
この記事では、Mysql WorkBenchのインストールと設定のグラフィックチュートリアルを参考ま...
1. レビューMySQL の起動後にバッファ プールが初期化されます。バッファ プールは N 個の空...
目次背景element-ui の自動構築はどのように機能しますか?メイクファイル新しい.jsファイル...
LinuxにMySQLがすでにインストールされているかどうかを確認する sudo service m...
この記事では、MySQL 8.0.16 Win10 zip版のインストールと設定のグラフィックチュー...
この記事では主に、Tencent TIM インスタント メッセージングを Vue と統合する方法を紹...
この記事では、MySQL 5.7 で追加された json フィールド タイプの使用方法を例を使って説...
まず、Tomcatフォルダを作成します。Dockerの設定を容易にするために、ルートディレクトリに直...
目次1. 優先キューの紹介2. 優先キューのカプセル化1. 優先キューの紹介通常のキューに要素が挿入...
MySQLデータベースをダウンロードするには、https://dev.mysql.com/down...
Linuxファイアウォールの状態を確認する方法1. 基本操作 # ファイアウォールのステータスを表示...
MySQL データベースが Centos7 システムにインストールされており、オペレーティング シス...
最近、Ant Design Blazor コンポーネント ライブラリにマルチタブ コンポーネントを実...
この記事では、MySQL マスター/スレーブ データベースの構築方法について説明します。ご参考までに...
序文vsftp は使いやすく安全な FTP サーバー ソフトウェアです。システムユーザーまたは仮想ユ...