OnceIO は、OnceDoc エンタープライズ コンテンツ (ネットワーク ディスク) の基盤となる Web フレームワークであり、テンプレート ファイルと静的ファイルの完全なキャッシュを実現でき、実行には I/O 操作がまったく必要なく、クライアント キャッシュの最適化、GZIP 圧縮、など (最初の圧縮のみ) は非常に優れたパフォーマンスを発揮し、サーバーのコストを節約します。そのモジュラー機能により、Web を分散方式で保存できます。つまり、拡張パッケージにはフロントエンド、バックエンド、およびデータベース定義が含まれており、ディレクトリを追加/削除することで関数を削除し、真のモジュラー拡張を実現できます。 OnceIOの使い方を紹介する連載記事です。
この章では、OnceIO を使用してファイル アップロード機能を実装する方法を説明します。
Web ページ ファイルにフォームを構築します
例として、ファイル アップロード機能のみを備えた単純な Web ページ file.html を取り上げます。
<!DOCTYPE html> <html> <body> <form method="post" enctype="multipart/form-data" action="/file/upload"> <input type="file" name="file" /><br> <input type="submit" value="Upload" /> </form> </body> </html>
ブラウザの表示効果は次のようになります。
空白のバーまたは「参照...」ボタンを使用すると、ファイル参照ウィンドウを開いて、アップロードする必要のあるファイルを選択できます:
サーバー受信ファイルロジックを確立します
サーバーファイルのwebsvr.jsコードは次のようになります:
var fs = require('fs') var path = require('path') var onceio = require('../onceio/onceio') var app = onceio() app.get('/', function(req, res){ res.render('file.html') }) app.file('/file/upload', function(req, res) { var fileInfo = req.files.file || {} fs.link(fileInfo.path, path.join('./fileStore', fileInfo.name)) res.send('File Uploaded Successfully') }).before(function(req, res) { var contentLength = req.headers['content-length'] || 0 if (contentLength > 1048576) { res.send({ error: 'Error: File Size Limit (1 MB) Exceeded' }) } else { return true } })
var fs = require('fs') と var path = require('path') は、それぞれ Node.js が提供するファイル操作用のファイル システム (fs) モジュールとファイル パスを処理するパス モジュールをインポートします。
app.file(path, callback).before(callback) は app.use(path, callback, {file: true}).before(callback) と同等で、アップロードされたファイルを処理するミドルウェアです。
ファイルがアップロードされると、そのサイズ、ストレージアドレス、名前、形式、および変更時刻が req.files の file 属性に配置されます (名前はタイプ「file」の入力タグ内の name の値です)。そのサイズ情報は、req.headers の content-length 属性に配置されます。
before 関数
before は、OnceIO と他の Web フレームワークの主な違いの 1 つです。最高のパフォーマンスを得るために、ファイルを受信する前に、サイズ、タイプなどの基本的な検証を実行できます。 true を返すと、検証が成功してファイルの受信が開始されることを示します。そうでない場合は、接続が閉じられ、アップロードがキャンセルされます。以前は、セッションがファイルまたはデータベース Redis に存在する可能性があり、セッションの取得は時間がかかる非同期プロセスであるため、req.session オブジェクトは使用できませんでした。 before 関数は、ファイルの合法性を即座に判断する必要があります。
この例では、before コールバック関数は、req.headers の content-length に基づいて、アップロードされたファイルがサイズ制限を超えているかどうかを判断します (開発者は、if ステートメントの定数を変更することで、ファイルのアップロード サイズの上限を変更できます。 content-length の単位はバイト、1024 * 1024 は 1 MB を表します)、それを超えた場合、ファイルはアップロードされず、超えていない場合、関数の戻り値は true です。 、サーバーは引き続き app.file のコールバック関数を実行して、一時アドレスからファイルを転送します。アドレスは指定されたストレージアドレスに転送され、ファイルはここにアップロードされます。
ファイル名が重複する問題を解決する
現在のサーバープログラムではファイル名が重複する問題を解決できません。ユーザーが同じ名前のファイルをアップロードすると、サーバーはファイルがすでに存在するというエラーを返します。この問題を解決するには、ファイルのメインファイル名と拡張子名の間にタイムスタンプを追加します。この処理の関数コードは次のとおりです。
var timestampName = function(fileName){ // get filename extension var extName = path.extname(fileName) // get base name of the file var baseName = path.basename(fileName, extName) // insert timestamp between base name and filename extension // the plus sign ('+') before new Date() converts it into a number return baseName + +new Date() + extName }
次に、fs.link ステートメントの fileInfo.name を次のように置き換えます。 timestampName(fileInfo.name):
fs.link(fileInfo.path, path.join('./fileStore', timestampName(fileInfo.name)))
改良されたサーバー プログラムにより、ユーザーは同じ名前のファイルをアップロードできるようになります。例として、「cache_workflow.png」という名前のファイルを 5 回アップロードすると、サーバーのファイル ストレージ アドレスに 5 つの名前が表示されます。 「cache_workflow」で始まるがタイムスタンプが異なるファイル: