enctype='multipart/form-data'ってなんだ?

こんにちは、MUGENUPアルバイトの倉成です。

今回は僕が前々から気になっていた、フォームからファイルを送信するときのおまじないenctype="multipart/form-data"について調べてみたので、得られた知識をまとめて見ようと思います。

また、マルチパートの情報を検索していると、HTMLのフォームだけではなく、メールのマルチパートの情報に当たることも多くありました。 調べてみると、HTMLの仕様と電子メールの仕様が似ているのは、どうやら歴史的な経緯があるようなので、後半ではインターネット成長の歴史についても少しだけ触れてみようと思います。

multipart/form-data: ファイルを送るおまじない

それでは、フォームでファイルをアップロードするシチュエーションを考えましょう。

ファイルアップロードをする場合input要素は<input type="file" />を使い、その親のform要素には以下のようにenctype="multipart/form-data"と書く必要があります。

f:id:mgnup:20140827094606p:plain

<form action="URI" method="post" enctype="multipart/form-data">
  <input type="file" name="file" />
</form>

さて、このおまじないenctype="multipart/form-data"はなぜ必要なのでしょうか?

Firebugを使ってリクエストを見る

今回はenctypeの有無によりHTTPリクエストのパラメータがどのように変化するかFirefoxプラグインであるFirebugを使って調べてみようと思います。

なお、今回使用するhtmlのソースコード

<html>
  <!-- enctype指定あり -->
  <form action="http://localhost:4567" method="post" enctype="multipart/form-data">
    <input type="file" name="datafile" />
    <input type="submit" name="submit_btn" />
  </form>
  <!-- enctype指定なし -->
  <form action="http://localhost:4567" method="post">
    <input type="file" name="datafile" />
    <input type="submit" name="submit_btn" />
  </form>
</html>

で、送信するファイルは

hello world!

hogehoge
fugafuga

とします(添付ファイル名はsample.txtです)。

さて、それぞれを試したところFirebugは以下の画像のようになりました。

enctype指定あり

f:id:mgnup:20140826195719p:plain

enctype指定なし

f:id:mgnup:20140826195727p:plain

enctype指定ありでは、Content-DispositionContent-Typeなど添付ファイルに関する情報とともに、ファイルの本文の情報が存在することが分かります。今回はテキストですが、画像や音声などバイナリの情報でも、同様にここにデータが格納されます。 また、--------で始まる行があることも特徴的です。

enctype指定なしでは、filedataにファイル名の情報のみが与えられていて、添付ファイルの情報は見当たりません。 どうも、inputエリアにファイル名のみを指定した

f:id:mgnup:20140825232727p:plain

と同様な印象を受けます。 つまり、enctype="multipart/form-data"を指定しない場合、添付ファイルの情報を送信できていないので、サーバー側では添付ファイルを扱えないという事になりそうです。

なお、-----------------------------146617270317...のような区切り文字をboundaryと呼び、この区切りを使って複数のパートに分割することからマルチパートと呼ばれているようです。boundaryを使うと入れ子構造も再現できるようです、興味のある方は以下のリンクが詳しくまとまっているので御覧ください。

フォームよるファイルアップロードの仕様 - Jakarta Commons FileUploadの利用手順

メールの場合は

boundaryを使ってファイルの情報を送信するというのがmultipart/form-dataの仕組みでした。 しかし、冒頭で述べたようにメールにも同様のマルチパートという仕組みがあるようです。 では、これまで見てきたフォームのマルチパートはメールのマルチパートとどのような関係があるのでしょうか?

ここでは「Webを支える技術」の引用をさせていただきます。

HTTPの最初のバージョン0.9にはヘッダがありませんでした。HTTPの仕様策定が進められるに従って、HTTPで転送する本文のメタデータを表現するために電子メールのメッセージ仕様(RFC822)のヘッダ形式を借りてくる形で追加されました。

Webを支える技術 P.126

つまり本記事では、formつまりHTTPのマルチパートを先に紹介していたのですが時系列で言うとこれは逆で、HTTPの仕様策定時に電子メールの仕様を参考にしたというのが歴史的な流れのようです。マルチパートに限らず、HTTPの仕様が電子メールの仕様に似ているのはこのような経緯があるためなのですね。

f:id:mgnup:20140825232655p:plain

なぜ電子メールの仕様にマルチパートが加わったのか(MIMEが策定されたのか)については

MIME の基礎

で詳しく解説されています。

ざっくりというとMIME策定前の仕様ではメールのヘッダ・本文がASCII限定で、日本語など非ASCIIの言語が正しく認識できなかったり、添付ファイルがうまく扱えなかったという問題があったようです。

multipart/alternative:textとhtmlを同時送信

「マルチパート メール」などで検索してヒットする記事にはmultipart/alternativeに関する記事も多いようです。

multipart/alternativeはマルチパートの構造を利用して一つのメールにtext版とhtml版の2つの内容を含めて送信し、メーラーの設定次第でtexthtmlを選択して表示できるものです。

-----------------------------1948084979928559891542425288
はじめに

こんにちはMUGENUPの倉成です。

-----------------------------1948084979928559891542425288 
<h1>はじめに</h1>

<b>こんにちは</b>MUGENUPの倉成です。
-----------------------------1948084979928559891542425288--

こんなメールを送ると、メーラーの設定次第でプレーンテキストでもリッチテキストでも表示できるようになるわけですね。

さいごに

enctypeを見るたびに「これ、なんだろうなぁー」と思っていたことから始まり、調べて行ったらインターネット成長の歴史的な経緯まで知ることができて、楽しい夏休みの自由研究となりました。 RFCの仕様も機会があればもう少し読んでみようと思います。

HTTPの仕様やRFC策定の歴史については山本陽平さんの「Webを支える技術」を参考にさせていただきました。 URI設計やステータスコードJSON、HTTPメソッドの使い分けなど基礎的な情報が網羅されているので、特にWebプログラミングが初めてのエンジニアさんにおすすめの一冊です。