XMLHttpRequestオブジェクトを使用してファイルをアップロードする方法についてネットで調べているのですが、手段が多種多様でありどのように実装していけばいいかがわかりません。
MDNでは以下のように記載がされていました。
バイナリコンテンツ(ファイルのアップロードなど)を送信する最善の方法は、ArrayBuffersまたはBlobをsend()メソッドと組み合わせて使用することです。
今現在はFormDataオブジェクトを利用して処理をしているのですが、FormDataオブジェクトを利用してアップロードするのと上記のArrayBuffersもしくはBlobを使用するのとでは何か違いがあるのでしょうか?
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
ベストアンサー
Ⅰ. はじめに
MDNでは以下のように記載がされていました。
バイナリコンテンツ(ファイルのアップロードなど)を送信する最善の方法は、ArrayBuffersまたはBlobをsend()メソッドと組み合わせて使用することです。
MDNのどこに書かれていたかすぐに分かりません。
回答者やGoogle等から調べてきた方の負担になるのでソースを明記して下さい。
また、ArrayBuffers
とは書かれていません。正しく引用して下さい。
以下MDNから原文を引用します。
日本語 MDN
バイナリコンテンツを送信する (ファイルのアップロードなど) 最良の方法は、ArrayBufferView または Blobs と send() メソッドを組み合わせることです。
最終更新者: atotto, 2016/03/31 0:15:48
https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest
英語 MDN
The best way to send binary content (e.g. in file uploads) is by using an ArrayBufferView or Blobs in conjunction with the send() method.
Last updated by: Bzbarsky, Sep 15, 2017, 7:30:55 PM
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send
Ⅱ. 質問への回答
FormData
を利用するデメリットは思いつく限り2点あります。
Content-Length
が必ず実ファイルのサイズより大きくなります。boundary
で区切られたリクエストデータを解析する時間が必要になります。
画像のようなバイナリファイルを1回のリクエストで1枚だけアップロードするといったシーンでは、無駄が無くなる為「最良の方法」としてMDNでは推奨しているのかと思います。
※ArrayBuffer
またはBlob
を利用するとFormData
のデメリットで挙げた2点の無駄が無くなります。
正直な所、どちらも気にする程リクエストサイズが増えたり、気にする程時間がかかったりする訳ではありません。
あくまで「最良の方法」として推奨しているだけかと思います。
何故、Content-Length
が必ず実ファイルのサイズより大きくなるかについては、
FormData
を利用するとContent-Type
がmultipart/form-data
になります。
multipart/form-data
の場合boundary
が必須となります。
よって、Content-Length
が必ず実ファイルのサイズより大きくなります。
FormDataの生HTTPリクエスト
txt
1POST http://localhost/upload HTTP/1.1 2Host: localhost 3Connection: keep-alive 4Content-Length: 255731 5Pragma: no-cache 6Cache-Control: no-cache 7Origin: http://localhost 8User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36 9Content-Type: multipart/form-data; boundary=----WebKitFormBoundarymU5bQKpOUibTgADX 10Accept: */* 11DNT: 1 12Referer: http://localhost/1.html 13Accept-Encoding: gzip, deflate, br 14Accept-Language: ja 15 16------WebKitFormBoundarymU5bQKpOUibTgADX 17Content-Disposition: form-data; name="image"; filename="a.jpg" 18Content-Type: image/jpeg 19 20 JFIF H H 21(略) 22 23------WebKitFormBoundarymU5bQKpOUibTgADX-- 24
ArrayBufferまたはBlobの生HTTPリクエスト
txt
1POST http://localhost/upload HTTP/1.1 2Host: localhost 3Connection: keep-alive 4Content-Length: 255547 5Pragma: no-cache 6Cache-Control: no-cache 7Origin: http://localhost 8User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36 9Content-Type: image/jpeg 10Accept: */* 11DNT: 1 12Referer: http://localhost/1.html 13Accept-Encoding: gzip, deflate, br 14Accept-Language: ja 15 16 JFIF H H 17(略)
サンプルプログラム
html
1<html> 2 <body> 3 <form id="form1" method="post" action="/upload"> 4 <input type="file" id="file" name="file" onchange="handleFiles(this.files)" /> 5 </form> 6 7 <script> 8 function handleFiles(files) { 9 var file = files[0]; 10 11 // ArrayBuffer 12 var reader = new FileReader(); 13 reader.readAsArrayBuffer(file); 14 reader.onload = function () { 15 upload(reader.result, file.type); 16 }; 17 18 // Blob 19 upload(file); 20 21 // FormData 22 var formData = new FormData(); 23 formData.append("image", file); 24 upload(formData); 25 } 26 27 function upload(data, type = null) { 28 var xhr = new XMLHttpRequest(); 29 xhr.open(form1.method, form1.action); 30 if (type !== null) { 31 xhr.setRequestHeader('Content-Type', type); 32 } 33 xhr.send(data); 34 } 35 </script> 36 </body> 37</html>
投稿2017/10/28 07:20
編集2017/10/28 07:23総合スコア769
0
きちんとソースを挙げられないのですが、FormDataオブジェクトで送信する場合はフォームと同じ取り扱いだったと思います。
なのでContent-Type: multipart/form-data
になるかと思います。以前にform
エレメントを使わずにFormDataオブジェクトにblobをつっこんでjQueryでXMLHttpRequest通信をしようとしたときに、明示的にヘッダにContent-Type: multipart/form-data
を設定しないと動作しなかった覚えがあります。
一方で、Blob
の場合は、Blob.type
がMIMEタイプ、という取り扱いになっており、送信時に使われるようです。またArrayBuffers
(TypedArray
)で送信する時には、Content-Type
が明示されていないようでした(Firefoxの場合)
もっと詳しい内容や仕様については、他の詳しい回答者をお待ちください。
投稿2017/10/28 00:57
総合スコア35811
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。