Node.js でのブレークポイント再開の実装

Node.js でのブレークポイント再開の実装

序文

通常のビジネスニーズ: 写真、Excel などをアップロードします。結局のところ、数 MB のサイズのファイルをサーバーにすばやくアップロードできます。
数百 MB または GB のビデオなどの大きなファイルをアップロードする場合は、より長い時間待つ必要があります。

これにより、対応する解決策が生まれます。大きなファイルをアップロードする際の一時停止、切断、ネットワーク状態の悪化などに対して、スライス + ブレークポイント再開を使用すると、上記の状況を適切に処理できます。

ソリューション分析

スライス

アップロードした動画を分割します。具体的な操作は以下のとおりです。

File.slice(start,end): 新しいblobオブジェクトを返します

  • BLOBの開始バイトをコピーする
  • BLOBの最後のバイトをコピーする

履歴書のダウンロード

各スライスをアップロードする前に、同じファイルのアップロードされたスライスの数を読み取るようにサーバー インターフェイスに要求します。新しいファイルがアップロードされた場合、サーバーは 0 を返し、それ以外の場合はアップロードされたスライスの数を返します。

具体的な解決プロセス

このデモでは、重要なアイデアとメソッドが紹介されています。このコードに基づいて、ファイル制限、ファイル重複の lastModifiedDate 検証、キャッシュされたファイルの定期的なクリア、その他の機能拡張などの他の機能を追加できます。

html

<input class="ビデオ" type="ファイル" />
<button type="submit" onclick="handleVideo(event, '.video', 'video')">
    送信</button>

スクリプト

let count = 0; // アップロードするファイルインデックスを記録する const handleVideo = async (event, name, url) => {
// ブラウザのデフォルトのフォームイベントを防止する event.preventDefault();
currentSize を document.querySelector("h2") に設定します。
files = document.querySelector(name).files とします。
// デフォルトのスライス数 const sectionLength = 100;
// 最初にインターフェイスに要求して、サーバー上にファイルが存在するかどうかを確認します // count が 0 の場合、最初のアップロードです。count が 0 でない場合、ファイルはサーバー上に存在し、アップロードされたスライスの数が返されます count = await handleCancel(files[0]);

//スライスを格納する配列オブジェクトを宣言します。let fileCurrent = [];
// ループファイルファイルオブジェクト for (const file of [...files]) {
  // 各スライスのサイズを取得します。let itemSize = Math.ceil(file.size / sectionLength);
  // ファイル サイズをループし、ファイル BLOB を配列に格納します。let current = 0;
  (現在値; 現在値 < ファイルサイズ; 現在値 += アイテムサイズ) {
    fileCurrent.push({ ファイル: file.slice(current, current + itemSize) });
  }
  // axios は手動キャンセル要求をシミュレートします。const CancelToken = axios.CancelToken;
  const ソース = CancelToken.source();
  // アップロードを再開するときに、スライスの数を処理します。アップロードされたスライスがすでにアップロードされている場合は、再度アップロードを要求する必要はありません。fileCurrent =
    count === 0 ? fileCurrent: fileCurrent.slice(count, sectionLength);
  // ループスライスリクエストインターフェース for (const [index, item] of fileCurrent.entries()) {
    //リクエストの一時停止をシミュレートする||ネットワークが切断された場合if (index > 90) {
      source.cancel("リクエストをキャンセル");
    }
    // ファイル関連情報を保存します // ファイルはスライス BLOB オブジェクトです // ファイル名はファイル名です // インデックスは現在のスライス番号です // 合計は合計スライス数です let formData = new FormData();
    formData.append("ファイル", item.file);
    formData.append("ファイル名", file.name);
    formData.append("total", sectionLength);
    formData.append("index", インデックス + カウント + 1);

    待機axios({
      URL: `http://localhost:8080/${url}`,
      メソッド: "POST",
      データ: フォームデータ、
      キャンセルトークン: ソーストークン、
    })
      .then((応答) => {
        // 進捗状況を表示するためのデータを返します currentSize.innerHTML = `progress${response.data.size}%`;
      })
      .catch((エラー) => {
        コンソールログ(エラー);
      });
  }
}
};

// アップロードされたファイルが存在するかどうかを確認するためのリクエストインターフェース // count が 0 の場合、存在しないことを意味します。count が 0 でない場合、対応する数のスライスがアップロードされています。const handleCancel = (file) => {
戻り値: axios({
  メソッド: "post",
  URL: "http://localhost:8080/getSize",
  ヘッダー: { "Content-Type": "application/json; charset = utf-8" },
  データ: {
    ファイル名: ファイル名、
  },
})
  .then((res) => {
    res.data.count を返します。
  })
  .catch((エラー) => {
    コンソールログ(エラー);
  });
};

ノードサーバー

// Express を使用してサーバー API を構築します
定数 express = require("express");
// ファイルをアップロードするためのロジックコードを導入します。const upload = require("./upload_file");
// すべての応答を処理し、クロスドメインを設定します app.all("*", (req, res, next) => {
  res.header("アクセス制御許可オリジン", "*");
  res.header("アクセス制御許可ヘッダー", "X-Requested-With");
  res.header("アクセス制御許可メソッド", "PUT、POST、GET、DELETE、OPTIONS");
  res.header("Access-Control-Allow-Headers", "Content-Type, X-Requested-With");
  res.header("X-Powered-By", " 3.2.1");
  res.header("Content-Type", "application/json;charset=utf-8");
  次();
});
express() は、定数です。

app.use(bodyParser.json({ type: "application/*+json" }));
// ビデオのアップロード(現在のスライス数を照会)
app.post("/getSize", upload.getSize);
// ビデオアップロードインターフェース app.post("/video", upload.video);

// ローカルポートのリスニングを有効にする app.listen(8080);

アップロードファイル

// ファイルアップロードモジュール const formidable = require("formidable");
// ファイル システム モジュール const fs = require("fs");
// システムパスモジュール const path = require("path");

//ファイルストリームへの書き込み操作 const handleStream = (item, writeStream) => {
  // 対応するディレクトリファイルバッファを読み取る
  const readFile = fs.readFileSync(item);
  // 読み取りバッファ || チャンクをストリームに書き込みます writeStream.write(readFile);
  // 書き込み後、一時的に保存したスライスファイルをクリアします。fs.unlink(item, () => {});
};

// ビデオアップロード(スライス)
module.exports.video = (req, res) => {
  // 解析オブジェクトを作成します。const form = new formidable.IncomingForm();
  // ビデオファイルのアップロードパスを設定します。let dirPath = path.join(__dirname, "video");
  フォームにアップロードするDirを指定します。
  // アップロードされたファイル名のサフィックスを保持するかどうか form.keepExtensions = true;
  // err エラーオブジェクトには、解析が失敗した場合のエラー情報が含まれます // fields には、バイナリ以外の formData キーと値のオブジェクトが含まれます // file オブジェクトタイプには、アップロードされたファイルに関する情報が含まれます form.parse(req, async (err, fields, file) => {
    // アップロードされたファイル BLOB オブジェクトを取得します。let files = file.file;
    // 現在のスライスのインデックスを取得します
    index = fields.index; とします。
    // スライスの合計数を取得します。let total = fields.total;
    // ファイル名を取得します。let filename = fields.filename;
    // アップロードファイル名を書き換えて一時ディレクトリを設定する let url =
      ディレクトリパス +
      "/" +
      ファイル名.split(".")[0] +
      `_${インデックス}.` +
      ファイル名.split(".")[1];
    試す {
      // アップロードされたファイル名を同期的に変更します fs.renameSync(files.path, url);
      コンソールにログ出力します。
      // 非同期処理 setTimeout(() => {
        // 最後のスライスがアップロードされたかどうかを判断し、すべてのビデオをまとめて書き込みます if (index === total) {
          // 完全なビデオを保存するための新しいディレクトリを同期的に作成します。let newDir = __dirname + `/uploadFiles/${Date.now()}`;
          // ディレクトリを作成します fs.mkdirSync(newDir);
          // ファイルに書き込むための書き込み可能なストリームを作成します。let writeStream = fs.createWriteStream(newDir + `/${filename}`);
          fsList = [] とします。
          // すべてのスライスファイルを取り出して配列に格納します for (let i = 0; i < total; i++) {
            定数fsUrl =
              ディレクトリパス +
              "/" +
              ファイル名.split(".")[0] +
              `_${i + 1}.` +
              ファイル名.split(".")[1];
            fsList.push(fsUrl);
          }
          // スライスファイル配列をループし、ストリームに書き込みます for (let item of fsList) {
            handleStream(アイテム、writeStream);
          }
          // すべてを書き込んでストリームを閉じます write stream writeStream.end();
        }
      }, 100);
    } キャッチ (e) {
      コンソールログ(e);
    }
    res.send({
      コード: 0,
      メッセージ: 「アップロード成功」、
      サイズ: インデックス、
    });
  });
};

// ファイルスライスの数を取得します module.exports.getSize = (req, res) => {
  count = 0 とします。
  エンコードを"utf8"に設定します。
  req.on("データ", 関数(データ) {
    name = JSON.parse(データ) とします。
    dirPath = path.join(__dirname, "video"); とします。
    // アップロードされたスライスファイルの数を計算します。let files = fs.readdirSync(dirPath);
    files.forEach((アイテム, インデックス) => {
      URLを=にする
        名前.ファイル名.split(".")[0] +
        `_${インデックス + 1}.` +
        名前.ファイル名.split(".")[1];
      if (files.includes(url)) {
        ++カウント;
      }
    });
    res.send({
      コード: 0,
      メッセージ: 「アップロードを続けてください」
      カウント、
    });
  });
};

論理的分析

フロントエンド

まず、アップロードをリクエストして、ファイルが初めてアップロードされたものか、対応するスライスがすでに存在するかを確認します。

  • ファイルが初めてアップロードされると、スライスは0から始まります。
  • ファイルにすでに対応するスライスがある場合、アップロード要求はスライス番号から開始されます。

スライス配列をループし、各スライスファイルをアップロードします。

  • 手動一時停止要求をシミュレートし、スライス数が90を超えると要求をキャンセルします。

サーバ

クエリファイルのファイル名を受け取り、一時保存ファイルのアドレスを見つけ、対応するアップロードファイルが存在するかどうかを判断します。

  • ファイルが一度もアップロードされていない場合は 0 を返し、スライス番号は 0 から始まります。
  • ファイルがアップロードされている場合は、対応するスライスの数が返されます。

アップロードされたファイルスライスを受信し、一時ストレージディレクトリにファイルを保存します。

  • count と total を使用して、スライスがアップロードされたかどうかを判断します。
  • アップロード後、ファイル保存ディレクトリを作成し、書き込み用の書き込み可能なストリームを作成します。
  • 対応する一時ファイルを抽出して配列に入れ、ファイルディレクトリ配列をループし、ファイルバッファを順番に読み書きします。
  • 書き込み後、書き込み可能なストリームを閉じます。

まとめ

上記のコードは、具体的な業務プロセスに応じて変更または逸脱する可能性があります。これは、具体的な実装方法の 1 つにすぎません。
この記事が皆様のお役に立てれば幸いです。文章に間違いがありましたらご指摘いただければ幸いです。

上記コードのアドレス: https://github.com/Surprise-ling/uploadFiles

Node.js ブレークポイント レジュームの実装に関するこの記事はこれで終わりです。より関連性の高い Node.js ブレークポイント レジュームのコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Node.js をベースに大きなファイルを分割してアップロードする例
  • Node.jsにおけるファイルブレークポイント再開の原理と方法のまとめ
  • Node.jsはブレークポイント再開を実装する
  • React+Nodeは、大きなファイルを分割してアップロードし、数秒でアップロードを再開するというアイデアを実現します。

<<:  複数の .sql ファイルを MySQL に効率的にインポートする方法の詳細な説明

>>:  nginx のロケーションと書き換えの使用法の詳細な説明

推薦する

XHTML CSS ウェブサイトデザインの利点と問題点

XHTML は現在国際的に推奨されている標準的な Web サイト設計言語です。Webjx.com も...

Ubuntu 20.04 デスクトップのインストールとルート権限の有効化および SSH インストールの詳細

記事は主にUbuntu 20.04の簡単なインストールプロセスを記録し、インストール後に国内ソースを...

前後の秒、分、時間、日数を取得するMySQLデータベース

現在の時刻を取得します: current_timestamp を選択します。出力: 2016-06-...

IE6/7 は混乱するだろう: 空のテキスト ノードの高さの問題

序文: ietester でドキュメント コードを表示するには、debugbar を使用します。すべ...

W3C チュートリアル (3): W3C HTML アクティビティ

HTML は、World Wide Web 上で公開するために使用されるハイブリッド言語です。 XH...

Jenkinsはマイクロサービスをパッケージ化してDockerイメージを構築し、実行します。

目次環境の準備始める1. GitLabリモートリポジトリがマイクロサービスプロジェクトを作成する2....

MySQL メモリテーブルと一時テーブルの使用方法の詳細な説明

MySQL メモリ テーブルと一時テーブルの使用メモリテーブル: セッション 1 $ mysql -...

MySQL ストアド関数の詳細な紹介

目次1. ストアド関数を作成する2. ストアド関数の呼び出し3. 保存された関数を削除する4. スト...

Ubuntuがインターネットに接続できない場合の解決策

問題の説明:デスクトップ コンピューターとキャンパス ネットワークを使用して、有線モードでインターネ...

SSH接続を介してXshellを使用したUbuntu 20.04で報告されたサービス問題の詳細な説明

1. 最近、Ubuntu の新しいバージョンをインストールしました。/etc/ssh/sshd_co...

CSS で「プラス記号」効果を実装するためのサンプルコード

以下に示すプラス記号の効果を実現するには: この効果を実現するには、div 要素だけが必要です。 b...

ティックアニメーション効果を作成するための svg+css または js

以前、上司からログイン後にチェックマークを表示できるプログラムを作るように言われたのですが、Baid...

Linux での Python のアップグレードと pip のインストールの詳細な説明

Linuxバージョンのアップグレード: 1. まず、Linuxオペレーティングシステムに付属するPy...

Dockerカスタムネットワーク実装

目次1. コンテナ相互接続を実現するためにネットワークをカスタマイズする2. ネットワーク接続1. ...

Dockerfile テキストファイルの使用例の分析

Dockerfile は、イメージをビルドするために使用されるテキスト ファイルです。テキスト コン...