[フロントエンド] multipart/form-dataを理解してみよう
こんにちは、@yoheiMuneです。
ファイルアップロードを実装する時はいつも苦戦するのですが、
フロントエンドとバックエンドとのデータのやり取りでは、
そのコンテンツの種類を指定するために、
そして、
以降では、
なお、JavaScriptでの実装方法はこちらをご参照ください。
(以降ではHTTPリクエストの中身を扱いますが、それの理解は「HTTPリクエストの中身を学ぶ」が役立ちます。)
また、
1つ目のデータは
2つ目のデータは
このように、複数のデータ型をまとめて扱うことができる形式が
また、サーバーサイドでは上記の形式を読み取って、適切にデータを受け取る必要があります。なかなか面倒な処理なので、この辺りは言語本体やライブラリに任せたいところですね。
MIME タイプ - HTTP | MDN
フォームよるファイルアップロードの仕様 - Jakarta Commons FileUploadの利用手順
いまさら聞けないHTTPマルチパートフォームデータ送信 - SATOXのシテオク日記
Content-Disposition - HTTP | MDN
フォームデータを送信する - ウェブ開発を学ぶ | MDN
最後になりますが本ブログでは、フロントエンド、Node.js、Python、Swift、Go言語、Linux、インフラ、Java、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時に、解決の糸口を見つけられる」そんな目標でブログを書き続けています。今後も役立つネタを書いていきますので、ぜひ本ブログのRSSやTwitterをフォローして貰えたら嬉しいです ^ ^
最後までご覧頂きましてありがとうございました!
ファイルアップロードを実装する時はいつも苦戦するのですが、
multipart/form-data
というデータ形式を理解できたらすんなりと実装できるようになりました。今日は、ファイルアップロードでは必須とも言えるmultipart/form-data
について、ブログにまとめました。目次
サンプルコード
本記事のサンプルをGithubに置いてあります。Node.JSのサーバーで実装しています。実際に動かすと理解の助けになると思いますので、必要あればご参照ください。コンテンツの種類とは
multipart/form-data
を扱う前に、まずは「コンテンツの種類」について理解する必要があります。フロントエンドとバックエンドとのデータのやり取りでは、
html
、javascript
、png
、json
など様々な種類のデータを扱います。その際に、どんなデータを扱っているのかを指定する必要があります。そのコンテンツの種類を指定するために、
MIME Type
という形式が利用されています。それをHTTPのヘッダ(Content-Type
ヘッダ)に付与して、送信先にコンテンツの種類を伝えます。例えば本サイトからHTMLを受け取ると、以下のヘッダが付与されます。// htmlファイルを受け取る場合のHTTPヘッダ Content-Type:text/html; charset=UTF-8上記は
MIME Type
がtext/html
で、送信内容がhtmlであることを表現しています。MIME Type
にはhtml以外にも様々な種類が存在します。text/plain : テキストファイル image/png : PNG画像 application/pdf : PDFファイル application/json : JSONファイル など(その他の形式はこちら)
そして、
MIME Type
の中の1つが、今回扱いたいmultipart/form-data
という形式です。これは複合データ型(=multipart)であることを表現します。これは1回のHTTP通信で、複数の種類(テキストやファイルなど)を一度に扱うことができます。以降では、
multipart/form-data
の中身に踏み込みます。multipart/form-dataとは
multipart/form-data
は、前述の通り複数の種類のデータを一度に扱える形式で、主な利用シーンはHTMLフォームです。特にファイルアップロードでよく利用されます。HTMLフォームで利用する
HTMLフォームで複合型を使うには、form
タグの属性でenctype="multipart/form-data"
を指定します。<!--multipart/form-data形式でPOSTする例--> <form method="POST" action="/upload" enctype="multipart/form-data"> <input type="text" name="message" value="Hello"/><br> <input type="file" name="file"/><br> <input type="submit" value="SUBMIT"/> </form>これを実際にPOSTすると、
multipart/form-data
形式でサーバーにデータが送信されます。なお、JavaScriptでの実装方法はこちらをご参照ください。
HTTPの送信データ
上記のフォームでファイルにa.txtを指定した場合について、具体的に見ていきます。(以降ではHTTPリクエストの中身を扱いますが、それの理解は「HTTPリクエストの中身を学ぶ」が役立ちます。)
HTTPヘッダ
この記事の最初で説明した通りHTTPヘッダには、Content-Type
が付与されます。Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryO5quBRiT4G7Vm3R7このデータ形式が
multipart/form-data
であることが分かります。また、
boundary=----WebKitFormBoundaryO5quBRiT4G7Vm3R7
という値が指定されていることがわかります。これはコンテンツの境界を示す文字列です。データ形式が複合型なので、1回の送信データでいくつかの種類のデータが含まれますが、それらを分けるために使います(具体的にはボディ部で使います)。この境界を示す文字列はリクエストごとに変わるため、手元で試した場合には別の文字列になります。HTTPボディ
続いて送信内容(HTTPボディ)です。以下の内容が指定されました。------WebKitFormBoundaryO5quBRiT4G7Vm3R7 Content-Disposition: form-data; name="message" Hello ------WebKitFormBoundaryO5quBRiT4G7Vm3R7 Content-Disposition: form-data; name="file"; filename="a.txt" Content-Type: text/plain aaa ------WebKitFormBoundaryO5quBRiT4G7Vm3R7--ボディは境界を示す文字列ごとに、複数のデータが存在することがわかります。
1つ目のデータは
name="message"
というキーで、値がHello
であることがわかります。2つ目のデータは
name="file"
というキーで、ファイル名がfilename="a.txt"
で、ファイルの種類がContent-Type: text/plain
で、ファイルの中身がaaa
であることがわかります。このように、複数のデータ型をまとめて扱うことができる形式が
multipart/form-data
形式です。中身まで見ると難しくないですね!参考までに
今回は説明のためにファイルにはテキスト形式を用いましたが、もちろん画像などのバイナリーデータも指定可能です。しかしその場合には、ファイルの中身(上記の場合はaaa
)がバイナリを表現する形式になるため、人の目では理解することができません(サンプルはこちら)。また、サーバーサイドでは上記の形式を読み取って、適切にデータを受け取る必要があります。なかなか面倒な処理なので、この辺りは言語本体やライブラリに任せたいところですね。
参考文献
以下が参考になりました。ありがとうございます。MIME タイプ - HTTP | MDN
フォームよるファイルアップロードの仕様 - Jakarta Commons FileUploadの利用手順
いまさら聞けないHTTPマルチパートフォームデータ送信 - SATOXのシテオク日記
Content-Disposition - HTTP | MDN
フォームデータを送信する - ウェブ開発を学ぶ | MDN
最後に
中身を理解できるとなんてことないですね。こんな感じのベーシックスキル、今後も定期的に身につけていきたい今日この頃です。最後になりますが本ブログでは、フロントエンド、Node.js、Python、Swift、Go言語、Linux、インフラ、Java、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時に、解決の糸口を見つけられる」そんな目標でブログを書き続けています。今後も役立つネタを書いていきますので、ぜひ本ブログのRSSやTwitterをフォローして貰えたら嬉しいです ^ ^
最後までご覧頂きましてありがとうございました!