ファイルのアップロードは、最新の Web アプリケーションの一般的な機能の 1 つです。このブログでは、アップロードされたファイルの処理方法を示すバックエンドの例を提供しながら、シンプルだが完全なフロントエンド ファイル アップロードの実装を検討します。フロントエンド言語として JavaScript を使用し、バックエンド環境として Node.js を組み合わせます。はじめましょう!
フロントエンドファイルのアップロード
まずはフロントエンドに注目してみましょう。HTML、CSS、JavaScript を使用して単純なファイル アップロード フォームを作成し、そのファイルを AJAX 経由でバックエンド サーバーに渡します。ここでは、フロントエンド開発の基本的な知識をすでに持っていることを前提としています。
1. HTMLの構造
まず、ファイル アップロード入力ボックス、アップロード ボタン、アップロードの進行状況と情報を表示する要素を含む HTML 構造を作成します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传示例</title>
</head>
<body>
<input type="file" id="videoUploader" accept="video/mp4, video/ogg">
<button id="uploadBtn">上传</button>
<p id="uploadInfo"></p>
<progress id="uploadProgress" value="0" max="100"></progress>
</body>
</html>
2. CSS スタイル (オプション)
必要に応じて、CSS スタイルを追加してページを美しくすることができます。
3. JavaScript ロジック
次に、JavaScript を使用してファイル アップロード ロジックを実装します。構成ファイルから始めて、アップロード関数と関連するヘルパー関数を実装します。
// config.js
// 导出一些常量,包括上传信息、允许上传的文件类型、块大小和上传接口的URL
// 这些常量将在前端和后端代码中使用
const BASE_URL = 'http://localhost:8000/';
export const UPLOAD_INFO = {
'NO_FILE': '请先选择文件',
'INVALID_TYPE': '不支持该类型文件上传',
'UPLOAD_FAILED': '上传失败',
'UPLOAD_SUCCESS': '上传成功'
}
export const ALLOWED_TYPE = {
'video/mp4': 'mp4',
'video/ogg': 'ogg'
}
export const CHUNK_SIZE = 64 * 1024;
export const API = {
UPLOAD_VIDEO: BASE_URL + 'upload_video'
}
// index.js
// 在闭包内部,定义一个立即执行的匿名函数,接受document作为参数
((doc) => {
// 获取页面上的一些元素
const oProgress = doc.querySelector('#uploadProgress'); // 上传进度条
const oUploader = doc.querySelector('#videoUploader'); // 文件上传输入框
const oInfo = doc.querySelector('#uploadInfo'); // 用于显示上传信息
const oBtn = doc.querySelector('#uploadBtn'); // 上传按钮
let uploadedSize = 0; // 已上传的文件大小,用于控制分块上传
// 初始化函数
const init = () => {
bindEvent(); // 绑定事件
}
// 绑定事件函数
function bindEvent() {
oBtn.addEventListener('click', uploadVideo, false); // 点击上传按钮触发上传函数
}
// 异步上传函数
async function uploadVideo() {
// 获取文件对象
const { files: [ file ] } = oUploader;
if (!file) {
// 检查是否选择了文件,如果没有则显示提示信息
oInfo.innerText = UPLOAD_INFO['NO_FILE'];
return;
}
if (!ALLOWED_TYPE[file.type]) {
// 检查文件类型是否被允许,如果不允许则显示提示信息
oInfo.innerText = UPLOAD_INFO['INVALID_TYPE'];
return;
}
// 获取文件的一些基本信息
const { name, type, size } = file;
const fileName = new Date().getTime() + '_' + name;
let uploadedResult = null;
oProgress.max = size;
oInfo.innerText = '';
while (uploadedSize < size) {
// 使用slice方法将文件切割成小块,实现分块上传
const fileChunk = file.slice(uploadedSize, uploadedSize + CHUNK_SIZE);
// 创建FormData对象,用于传递文件块和相关信息
const formData = createFormData({
name,
type,
size,
fileName,
uploadedSize,
file: fileChunk
});
try {
// 使用axios库发送POST请求,将文件块上传到后端
uploadedResult = await axios.post(API.UPLOAD_VIDEO, formData);
} catch (e) {
// 捕获异常,如果上传失败,则显示提示信息
oInfo.innerText = `${ UPLOAD_INFO['UPLOAD_FAILED'] }(${ e.message })`;
return;
}
// 更新已上传的文件大小和进度条
uploadedSize += fileChunk.size;
oProgress.value = uploadedSize;
}
// 上传成功后,显示上传成功的提示信息,并将文件输入框置空
oInfo.innerText = UPLOAD_INFO['UPLOAD_SUCCESS'];
oUploader.value = null;
// 根据后端返回的视频URL,创建一个视频元素并展示在页面上
createVideo(uploadedResult.data.video_url);
}
// 创建FormData函数,将文件块和相关信息添加到FormData对象中
function createFormData ({
name,
type,
size,
fileName,
uploadedSize,
file
}) {
const fd = new FormData();
fd.append('name', name);
fd.append('type', type);
fd.append('size', size);
fd.append('fileName', fileName);
fd.append('uploadedSize', uploadedSize);
fd.append('file', file);
return fd;
}
// 创建视频元素函数,用于在页面上展示上传成功的视频
function createVideo(src) {
const oVideo = document.createElement('video');
oVideo.controls = true;
oVideo.width = '500';
oVideo.src = src;
document.body.appendChild(oVideo);
}
init(); // 初始化,执行绑定事件函数
})(document);
-
依存関係をインポートします。
config.js
: アップロード情報、アップロードが許可されているファイル タイプ、ブロック サイズ、アップロード インターフェイスの URL など、いくつかの定数をエクスポートします。axios
: ファイル チャンクをバックエンドにアップロードするための HTTP リクエストを作成するためのライブラリ。
-
すぐに実行される匿名関数を作成します。
document
引数として受け入れ、オブジェクトdoc
を表すために使用します。document
- このアプローチにより、グローバル変数の汚染が回避され、コードが別のスコープで実行されることが保証されます。
-
ページ上の要素を取得します。
oProgress
: アップロードの進行状況バーを表す要素<progress>
。oUploader
: ファイル アップロード入力ボックスを表す要素<input type="file">
。oInfo
: アップロード情報を表示するために使用される要素<p>
。oBtn
: アップロード ボタンを表す要素<button>
。
-
初期化関数:
bindEvent()
アップロード ボタンがクリックされたときにイベント ハンドラーをバインドするために使用される関数を呼び出します。
-
バインディングイベント関数:
- このメソッドを使用して
addEventListener()
、アップロード ボタンのクリック イベント リスナーを追加します。 - アップロード ボタンをクリックすると、
uploadVideo()
ファイルをアップロードする関数がトリガーされます。
- このメソッドを使用して
-
非同期アップロード機能
uploadVideo()
:- ファイル オブジェクトを取得します。これは、
file
ファイル アップロード入力ボックスからoUploader
取得されます。 - ファイルが選択されているかどうかを確認し、選択されていない場合はプロンプトを表示して戻ります。
- ファイルの種類がアップロードを許可されているかどうかを確認し、許可されていない場合は、プロンプト メッセージを表示して戻ります。
- ファイル名、ファイルタイプ、ファイルサイズなど、ファイルに関する基本情報を取得します。
- ループを使用して
while
、ファイルを分割してアップロードします。file.slice()
ファイルを小さなチャンクに分割するメソッドを使用します(チャンク サイズCHUNK_SIZE
は定数によって定義されます)。FormData
バックエンドに渡すためのファイル チャンクと関連情報を追加するオブジェクトを作成します。- このメソッドを使用して
axios.post()
、ファイルのチャンクをバックエンドで指定された URL (API.UPLOAD_VIDEO
定数で定義) にアップロードします。 - アップロードが失敗した場合は、例外をキャッチしてプロンプト メッセージを表示し、戻ります。
- アップロードされたファイルのサイズと進行状況バーの値を更新します。
- アップロードが完了すると、アップロードが成功したことを示すプロンプト メッセージが表示され、ファイル入力ボックスの値が空白に設定されます。
- バックエンドから返されたビデオ URL に従って、
createVideo()
関数を呼び出してページ上にビデオ要素を作成し、正常にアップロードされたビデオを表示します。
- ファイル オブジェクトを取得します。これは、
-
FormData
関数の作成createFormData()
:- バックエンドに渡すために、ファイル チャンクと関連情報を
FormData
オブジェクトに追加します。
- バックエンドに渡すために、ファイル チャンクと関連情報を
-
ビデオ要素関数の作成
createVideo()
:- これは、ページ上にビデオ要素を作成し、アップロードが成功した後にバックエンドによって返されるビデオ URL にビデオ URL を設定するために使用されます。
-
初期化関数
init()
:bindEvent()
アップロードボタンとイベントハンドラーをバインドする関数を実行します。
-
最後に、
init()
関数を呼び出すことによってフロントエンド コード全体が開始されます。
axios
フロントエンド コードにライブラリを含めます。これは、HTTP リクエストを行うための一般的なツールです。axios
実際のプロジェクトでは、ライブラリを HTML ファイルにインポートするか、同様の機能を持つ他のライブラリを使用する必要があります。
上記のコードでは、まず、アップロードが許可されるファイル タイプ、ブロック サイズなど、いくつかの定数を定義します。次に、イベント監視を通じて「アップロード」ボタンのクリックイベントをキャプチャし、アップロード機能を実行します。アップロード機能では、分割アップロードすることでファイルを複数の小さな部分に分割し、それらを 1 つずつバックエンドに送信して処理します。アップロード プロセス中に、アップロードの進行状況バーも更新され、アップロード情報がリアルタイムで表示されます。
バックエンドファイル処理
次に、バックエンド処理部分に焦点を当てましょう。Node.js と Express を使用して、フロントエンドからファイル チャンクを受信し、それらを完全なファイルにマージする単純なバックエンド サーバーをセットアップします。
1. 依存関係をインストールする
まず、プロジェクト ディレクトリにファイルを作成しpackage.json
、次のコマンドを実行して依存関係をインストールします。
上記のコードは、Express フレームワークを使用して単純なサーバーを構築し、ファイル アップロードのルートを設定します。/upload_video
インターフェイスを通じてファイル チャンクをアップロードでき、すべてのチャンクが受信されて完全なファイルにマージされるまで、バックエンドはアップロードされた情報に従ってファイル チャンクをサーバー側に保存します。
npm init -y
npm install express body-parser express-fileupload
2. バックエンドコード
次に、ファイルを作成しserver.js
、バックエンド コードを記述します。
const express = require('express');
const bodyParser = require('body-parser');
const uploader = require('express-fileupload');
const { extname, resolve } = require('path');
const { existsSync, appendFileSync, writeFileSync } = require('fs');
const app = express();
const PORT = 8000;
// 设置中间件,解析请求的JSON数据和文件上传
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(uploader());
// 设置静态资源目录,用于存放上传的临时文件块
app.use('/', express.static('upload_temp'));
// 允许跨域访问
app.all('*', (req, res, next) => {
res.header('Access-Control-Allow-origin', '*');
res.header('Access-Control-Allow-Methods', 'POST,GET');
next();
});
// 处理文件上传的POST请求,对应的URL为/upload_video
app.post('/upload_video', (req, res) => {
// 从请求体中获取传递的文件信息和文件块
const { name, type, size, fileName, uploadedSize } = req.body;
const { file } = req.files;
if (!file) {
// 检查是否传递了文件块,如果没有则返回错误信息
res.send({
code: 1001,
msg: 'No file uploaded'
});
return;
}
if (!ALLOWED_TYPE[type]) {
// 检查文件类型是否被允许,如果不允许则返回错误信息
res.send({
code: 1002,
msg: 'The type is not allowed for uploading.'
});
return;
}
const filename = fileName + extname(name);
const filePath = resolve(__dirname, './upload_temp/' + filename);
if (uploadedSize !== '0') {
if (!existsSync(filePath)) {
// 检查文件是否存在,如果不存在则返回错误信息
res.send({
code: 1003,
msg: 'No file exists'
});
return;
}
// 文件已存在,则将当前文件块追加到已有的文件中
appendFileSync(filePath, file.data);
// 返回成功信息和视频URL
res.send({
code: 0,
msg: 'Appended',
video_url: 'http://localhost:8000/' + filename
});
return;
}
// 第一个文件块,创建一个新文件并写入当前块的数据
writeFileSync(filePath, file.data);
// 返回成功信息
res.send({
code: 0,
msg: 'File is created'
});
});
// 启动服务,监听指定端口
app.listen(PORT, () => {
console.log('Server is running on ' + PORT);
});
-
依存関係をインポートします。
express
: Web サーバーを構築するための Express フレームワーク。body-parser
: リクエスト本文の JSON データを解析します。express-fileupload
: ファイルのアップロード要求を処理します。path
: ファイルパスを処理するための Node.js 組み込みモジュール。fs
: ファイル システム操作用の Node.js 組み込みモジュール。
-
Express アプリケーションを作成します。
const app = express(); const PORT = 8000;
-
ミドルウェアを使用します。
bodyParser
ミドルウェアは、JSON データを解析し、リクエスト本文のデータを形成するために使用されます。uploader
ミドルウェアは、ファイルのアップロード要求を処理するために使用されます。'/upload_temp'
アップロードされた一時ファイル ブロックを保存する静的リソース ディレクトリを設定します。
-
クロスドメイン アクセスの設定:
app.all()
このメソッドを使用して、クロスドメイン要求を許可する応答ヘッダーを設定します。 -
ファイルのアップロード要求を処理します。
- この定義を使用して
app.post('/upload_video', ...)
ファイル アップロードの POST リクエストを処理します。対応する URL は です/upload_video
。 - リクエストボディから渡されたファイル情報とファイルブロック(ファイル名、ファイルタイプ、ファイルサイズ、ファイルブロックのアップロード開始位置など)を取得します。
- ファイル ブロックが存在するかどうかを確認し、存在しない場合はエラー メッセージを返します。
- ファイルの種類が許可されているかどうかを確認し、許可されていない場合はエラー メッセージを返します。
- ファイル名とファイルの種類に基づいて新しいファイル名を生成し、ファイルの保存パスを計算します。
- 最初のファイル ブロックでない場合は、現在のファイル ブロックを既存のファイルに追加します。
- 最初のファイル ブロックの場合は、新しいファイルを作成し、現在のブロックのデータを書き込みます。
- アップロードされたビデオの URL を含む成功メッセージを返します。
- この定義を使用して
-
サービスの開始:
app.listen()
メソッドを使用してサーバーを開始し、指定されたポート (この場合は 8000) で待機します。
プロジェクトを実行する
これで、フロントエンドとバックエンドのコーディングが完了しました。次に、プロジェクトをローカルで実行して、ファイルのアップロード機能をテストする必要があります。
1. 一時アップロードディレクトリを作成します。
アップロードされたファイルの一時チャンクを保持するために、プロジェクトのルートにupload_temp
.py という名前のフォルダーを作成します。
2. サーバーを起動します
次のコマンドを実行してバックエンド サーバーを起動します。
node server.js
3. フロントエンドを起動する
フロントエンド コード (HTML、CSS、JavaScript) をフォルダーに配置し、フォルダーの下で HTTP サーバーを実行します (npm とyarn を使用しても問題ありません。npm install—npm run dev/yarn—yarn dev)。 、次のような使用http-server
:
npx http-server
http://localhost:8080
ここで、ブラウザを通じてフロントエンド ページ (通常は ) にアクセスします。サポートされているビデオ ファイル (.mp4 または .ogv 形式) を選択し、アップロード ボタンをクリックすると、アップロードの進行状況を示すアップロード進行状況バーが表示されます。アップロードが完了すると、アップロードが成功したことを示すメッセージがページに表示され、アップロードされたビデオ ファイルがページに表示されます。
結論
このブログでは、単純なフロントエンド ファイル アップロード機能を実装する方法と、Node.js と Express を組み合わせてファイル アップロードを処理するバックエンド サーバーを構築する方法を学びました。実際のプロジェクトでは、ニーズに応じてファイルアップロード機能を拡張・最適化することができます。このブログが、ファイル アップロードの基本原理と実践的な方法を理解するのに役立つことを願っています。読んでくれてありがとう!
フロントエンド ファイルのアップロードについてまだ質問がある場合、または他の技術的なトピックに興味がある場合は、ディスカッション グループに参加するか、注目してください。