HTML5 File API:サーバーへの複数のファイルのアップロード

(もちろんページをリロードせずに)サーバーに複数のファイルを同時にアップロードするタスクに再び直面したとき、私はファイルのajaxダウンロードをシミュレートできる、かなり不器用なjQueryプラグインを探してインターネットをサーフィンし始めました(同じプラグイン隠されたフレーム:javaおよびflashプラグインを拒否することがすぐに決定されました。 検索プロセスでは、次のhtml 5標準では、ファイルを操作する機能が大幅に拡張されるべきであり、これらの機能の一部が現在利用可能であることを思い出しました。 その結果、それらを実際にテストすることが決定されました。

サーバーへの複数の写真の同時アップロードの例を使用して、File APIの可能性を検討します。 記事の最後に、既製のソリューションがjQueryプラグインの形式で提示されています。


これを読みたくありません。既製のソリューションに興味があります。

したがって、File APIを使用する利点は何ですか。
  1. 外部プラグインからの独立
  2. ダウンロードプロセスを制御し、それに関する情報を表示する機能(プログレスバーは常にユーザーに忍耐を与えます)
  3. ダウンロードする前にファイルを読み取ってそのサイズを調べる機能(この例では、画像を含まないファイルを除外して画像のサムネイルを表示することができます)
  4. 標準ファイル選択フィールドを介して複数のファイルを一度に選択する機能
  5. ドラッグアンドドロップインターフェイスを使用してファイルを選択する機能。 はい、ファイルをドラッグアンドドロップして、デスクトップから、またはエクスプローラーなどから直接ダウンロードできます。

欠点のうち、ブラウザーでのサポートが不十分であることに注意することができます。 現在、File APIはFirefox≥3.6およびChrome≥6.0のみをサポートしています。 Safariはすぐに立ち上がると感じていますが、IEとOperaについては何も明らかではありません(誰かが情報を持っているかもしれません)。 もちろん、File APIがIE9 Betaをサポートしていないことは残念でした。IE開発者が現在html 5の豊富なサポートに向かっていることを考えると、これは奇妙なことです。

実際の例はhttp://safron.pro/playground/html5uploader/で見ることができます。以下は最も重要なコードスニペットです。

まず、htmlコードを扱います。 デフォルトの入力要素、ファイルをドラッグアンドドロップするためのコンテナ、および画像のサムネイルを配置するulリストが必要です。
<div> <input type="file" name="file" id="file-field" multiple="true" /> </div> <div id="img-container"> <ul id="img-list"></ul> </div> 


input要素にmultiple="true"属性が指定されていることを除いて、特別なことはありません。 これは、標準のファイル選択ダイアログで複数のファイルを一度に選択できるようにするために必要です。 ちなみに、Firefox 4以降、ブラウザーの開発者は、多くのタイプセッターが嫌う標準のファイル選択フィールドを非表示にし、非表示の要素のクリックイベントをトリガーしてダイアログを表示できるようになると約束しています。

JavaScriptに移りましょう(DOMの操作を簡単にするためにjQueryを使用したことに注意してください。何らかの理由でjQueryを放棄したい人は誰でも簡単にスクリプトを作り直すことができます)。 最初に、メインの役割で主演したhtml要素へのリンクを変数に保存します。 次に、標準のファイル選択フィールドと、ファイルをドラッグアンドドロップできる領域のイベントハンドラーを定義します。
  //  input   var fileInput = $('#file-field'); // ul-,     var imgList = $('ul#img-list'); // ,      drag and drop var dropBox = $('#img-container'); //        fileInput.bind({ change: function() { displayFiles(this.files); } }); //   drag and drop      dropBox dropBox.bind({ dragenter: function() { $(this).addClass('highlighted'); return false; }, dragover: function() { return false; }, dragleave: function() { $(this).removeClass('highlighted'); return false; }, drop: function(e) { var dt = e.originalEvent.dataTransfer; displayFiles(dt.files); return false; } }); 


どちらの場合も、ハンドラーでFileListオブジェクトにアクセスできます。これは、本質的にFileオブジェクトの配列です。 この配列はdisplayFiles()関数に渡され、そのテキストは以下に示されています。
  function displayFiles(files) { $.each(files, function(i, file) { if (!file.type.match(/image.*/)) { //    return true; } //   li     ,   progress bar, //      file,    File (  ) var li = $('<li/>').appendTo(imgList); $('<div/>').text(file.name).appendTo(li); var img = $('<img/>').appendTo(li); $('<div/>').addClass('progress').text('0%').appendTo(li); li.get(0).file = file; //   FileReader     ,     //     var reader = new FileReader(); reader.onload = (function(aImg) { return function(e) { aImg.attr('src', e.target.result); aImg.attr('width', 150); /* ...      ... */ }; })(img); reader.readAsDataURL(file); }); } 


Fileオブジェクトには、名前、サイズ、タイプなどのファイルに関するメタデータ(名前、サイズ、タイプのプロパティにそれぞれ、MIME形式(たとえば、image / gif)など)が含まれています。 ファイルの内容にアクセスするために、特別なFileReaderオブジェクトがあります。

displayFiles()関数内で、転送されたファイルの配列を調べ、最初に画像ではないものを取り除きます。 次に、画像ごとにliリストの要素が作成されます。img要素は配置されるまで空です(ファイルプロパティは、対応するオブジェクトを含む各li要素にも作成されます)。 その後、FileReaderのインスタンスが作成され、そのインスタンスにonloadハンドラーが定義されます。このインスタンスでは、データは以前に作成されたimg要素のsrc属性に直接転送されます。 FileReaderオブジェクトのreadAsDataURL()メソッドは、Fileオブジェクトをパラメーターとして受け取り、そこからデータの読み取りを開始します。 その結果、標準フィールドで選択されたすべての画像、またはブラウザに直接ドラッグされたすべての画像について、サムネイル(人工的に150ピクセルに縮小)が表示されます。

他にやるべきことは何ですか? 選択されたすべてのファイルをサーバーにダウンロードするだけです。 これを行うには、ボタンまたはリンクを作成します。クリックすると、作成されたすべてのli要素を調べ、そのファイルプロパティを読み取り、それをuploadFile()関数に渡すだけです。 ここでは、簡単にするために、関数を介してロードを実装し、 http://safron.pro/playground/html5uploader/にある実際の例では、追加のパラメーターを渡すことができる作成中に、すべてのロードアクションをuploaderObjectオブジェクトに収集しました。ロードプロセスに関する情報を取得するコールバック関数など。
 function uploadFile(file, url) { var reader = new FileReader(); reader.onload = function() { var xhr = new XMLHttpRequest(); xhr.upload.addEventListener("progress", function(e) { if (e.lengthComputable) { var progress = (e.loaded * 100) / e.total; /* ...      ... */ } }, false); /* ...     load  error  xhr.upload ... */ xhr.onreadystatechange = function () { if (this.readyState == 4) { if(this.status == 200) { /* ...  !   this.responseText ... */ } else { /* ... ! ... */ } } }; xhr.open("POST", url); var boundary = "xxxxxxxxx"; //   xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary); xhr.setRequestHeader("Cache-Control", "no-cache"); //    var body = "--" + boundary + "\r\n"; body += "Content-Disposition: form-data; name='myFile'; filename='" + file.name + "'\r\n"; body += "Content-Type: application/octet-stream\r\n\r\n"; body += reader.result + "\r\n"; body += "--" + boundary + "--"; if(xhr.sendAsBinary) { //   firefox xhr.sendAsBinary(body); } else { // chrome (   W3C) xhr.send(body); } }; //   reader.readAsBinaryString(file); } 


これにより、上記と同じ方法で、すでにおなじみのFileReaderオブジェクトのインスタンスが作成されます。 XMLHttpRequestが作成されるonloadイベントハンドラーが割り当てられます(残念ながら、ファイルはまだ提供されていないため、jQuery ajaxインターフェイスはまだ使用できません)。 2番目のバージョンのXMLHttpRequestでは、アップロードプロパティが表示されます。このプロパティには、進行状況、読み込み、およびエラーイベントを処理できるローダーオブジェクトが含まれます(詳細については、 http://www.w3.org/TR/XMLHttpRequest2/#xmlhttprequesteventtargetを参照してください )。 上記の例は、progressイベントの処理のみを示しています。 次に、リクエスト完了ハンドラーをリクエスト自体に割り当てます(ローダーオブジェクトのイベントとは対照的に、すべてのデータがダウンロードされ、サーバーからの応答が受信されたときに既に呼び出されています)、2つのヘッダーを追加して、リクエストボディを形成し、FileReaderオブジェクトのresultプロパティからデータを読み取ります。 その後、ダウンロードが開始されます。 現在のW3C仕様によると、XMLHttpRequestオブジェクトのsend()メソッドはパラメーターでバイナリデータを受け入れることができると理解されていますが、これはGoogle Chromeで正常に実装されていますが、Firefoxでは独自の方法で特別なsendAsBinary()メソッドを介して行われます。 したがって、送信を開始する前に、sendAsBinary()メソッドが要求オブジェクトで定義されているかどうかを確認し、定義されている場合はそれを使用します。

実際、それがすべてです。 html 5の承認と配布を楽しみにしています!

いくつかのリンク

  1. http://safron.pro/playground/html5uploader/-上記で説明したもの(およびその他のもの)の実用例
  2. http://safron.pro/playground/html5uploader/full.zip-コード全体はアーカイブにあります
  3. http://html5test.com-ブラウザーがHTML 5に準拠しているかどうかを確認する(非常に視覚的)
  4. http://playground.html5rocks.com-Googleのコードを実験するためのプラットフォーム(そのインターフェイスは、多数のGoogle APIを使用した人には馴染みがあるでしょう)


UPD
上記のすべての使用を簡素化するために、 jQueryプラグインが作成されました。 これを使用すると、可能であればFile APIを使用してファイルをアップロードし、そうでない場合は置換(通常のフォーム送信など)を実装できます。 労働者の要求に応じて、 コメンテーターコメントに従って、それをサポートするブラウザー(Chrome、Safari 5 +、FF 4+)のFormDataオブジェクトを介してダウンロードが追加されました。 プラグインファイルの一番上には、パラメーター、メソッド、および簡単な使用例の説明があります。 より完全な使用例はこちらにあります (これはこの記事の最初の例です。プラグインの使用のみをやり直し、サーバー側を含むその完全なコードはここからダウンロードできます [UPD2を参照])。

使用したソース

  1. https://developer.mozilla.org/en/using_files_from_web_applications-Mozilla開発者Webサイトのファイルインターフェイスに関する記事
  2. https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest-同じ場所でのXMLHttpRequestの使用に関する記事
  3. http://www.w3.org/TR/FileAPI/-W3C WebサイトのFile APIの現在の仕様
  4. http://www.w3.org/TR/XMLHttpRequest2/-同じ場所にある現在のXMLHttpRequest仕様



UPD2
glebovginユーザーのリクエストにより、プラグインが変更され、FileオブジェクトだけでなくBlobデータ(Blobオブジェクト)も直接送信できるようになりました。 これは、たとえばキャンバスのコンテンツをサーバーに送信する必要がある場合、または単に手動で生成されたデータがある場合に役立ちます。

デモ( 別のアドレスにわずかに移動)で、キャンバスから画像を送信する例が追加されました。 現時点では、この機能はFF、Chrome、IE10で機能します。

ソースコードがGitHubで利用可能になりました 。 コメント、提案、改善は大歓迎です!

Source: https://habr.com/ru/post/J109079/


All Articles