`application/x-www-form-urulencoded`形式と`multipart/form-data`形式は何が違うのか?

javascriptを使って画像をPOSTするアプリを作ろうとしている時、
「どのような形式でPOSTされているんだろう?」と気になったとこがありました。

手軽にPOSTできるツールcurlで形式を実際に確認しようとしました。
そのときに、POSTする形式には、application/x-www-form-urulencoded形式と
multipart/form-data形式の2種類あることを知ったのです。

結論からいうと、application/x-www-form-urulencodedは1つのオブジェクトをPOSTするため、
multipart/form-dataは複数のオブジェクトをPOSTために用意されているということでした。

形式が決められた当時は、そのような目的で作られてはいないと思いますが、
この理解が一番しっくり来ると思います。

この記事では、application/x-www-form-urulencoded形式と
multipart/form-data形式は何が違うのかについて解説します。

application/x-www-form-urulencoded形式とmultipart/form-data`形式とか、そもそも何なのか?メディアタイプ?MIMEタイプ?

そもそも、application/x-www-form-urulencoded形式とmultipart/form-data形式とか、
これらは何を表しているのでしょうか?

これらは、「メディアタイプ」、あるいは「MIMEタイプ」と呼ばれています。
ブラウザなどのツールからネットを介して何らかのデータを送る際に、「これは、〇〇形式のデータですよー」って
サーバーに伝えるために使われます。

〇〇は何でもいいのです。データがzipのときもあれば、
audio``video``photoshop``mp4などデータ形式は無数にあります。

それらのデータの種類を伝えるために、これが必要なのです。
この分類はどこが決めているのでしょうか?それは、RFC 2046で定義されています。
このうち、スラッシュの前半はトップレベルメディアタイプと呼ばれ、これがデータの大まかな種類を示しています。
スラッシュの後半はより具体的な種類をしてしています。

例えば、このように、

  • text…テキスト
  • image…画像
  • audio…音声
  • video…動画
  • application…その他

ところで、データの種類を分類する方法に「拡張子」がありますよね?
拡張子は、クリックしたときにどのようなソフトウェアで開くかを定義しています。
つまり、パソコン内のデータの形式は拡張子で管理されているのです。

しかし、ネット上では全く状況が違います。
拡張子はほとんど機能しません。
変わりに「メディアタイプ」、あるいは「MIMEタイプ」でデータ形式を管理しているのです。

application/x-www-form-urulencodedとはなんなのか?

先程、データ形式を分類した時、種類の1つだということを説明しました。
ここでは、application/x-www-form-urulencodedとはどのようなデータ形式なのかみ見ていきましょう。

まずは、スラッシュで分解します。

スラッシュの前半はapplication
applicationは便利な言葉(悪い意味で)です。
どのようなデータにも使えてしまうからです。
テキストかもしれないし、画像、動画、音楽かもしれない。圧縮データかもしれない。

ここだけだけでわかることは、「何かのデータ」ということでしょう。

次に、スラッシュの後半を見てみます。
x-www-form-urulencodedこのデータ形式は、mozilla.orgで定義されています。
このドキュメントによると、「キーとバリューを=でつなげ、それらのテキストをすべて&でつなげた形式」だそうです。
つまり、Mapを送れるのですね。

ここで、疑問がわきます。じゃあ、バイナリデータは送れないんじゃないか?とおもいますよね?
実は、base64というバイナリをテキスト形式に変換するアルゴリズムが存在します。

実質application/x-www-form-urulencodedはどのようなデータも扱えてしまうという事になります。
もちろん、その他のその他のコンテンツタイプもを使っても送れますが、
application/x-www-form-urulencodedは汎用性がとても高い点は事実です。

よって、application/x-www-form-urulencoded形式とは、
「1つの何らかのデータ」と言えると思います。

multipart/form-dataとは?

multipart/form-dataを簡単に言うと、複数のコンテンツをまとめたコンテンツタイプと言えると思います。
先程解説した、application/x-www-form-urulencodedを複数個まとめて送ることもできます。
つまりは、グルーピングですね。

例えば、下記のようなフォームでファイルを送信するとします。

<form action="test.php" method="post" enctype="multipart/form-data">
  <input type="text" name="text1">
  <input type="file" name="file1">
  <input type="submit">
</form>

enctype="multipart/form-data"を指定しているのは、
これが無指定だとapplication/x-www-form-urlencodedで送信されてしまうからです。
テキストとファイルは違うコンテンツタイプなので、ファイルが送信されないのです。

POST /test.php HTTP/1.1
Content-Type: multipart/form-data; boundary=------------------------do348x35ddd9489e3

--------------------------do348x35ddd9489e3
Content-Disposition: form-data; name="text1"

a&b
--------------------------do348x35ddd9489e3
Content-Disposition: form-data; name="file1"; filename="hello.txt"
Content-Type: text/plain

HELLO
--------------------------do348x35ddd9489e3--

ここで注目てほしいのは、「Content-Type」が2つあることです。
「multipart/form-data」形式で送信したので、
異なるコンテンツタイプがグループ化して送られたのです。

テキストだけのフォームだと、application/x-www-form-urulencodedで送られる?

Webフォームには、テキスト入力だけのフォームのあります。
formタグになにも指定しなければ、application/x-www-form-urulencodedで送られるんです。

例えば、下記のようなフォームです。

<form action="test.php">
  <input type="text" name="text1"><br>
  <input type="text" name="text2"><br>
  <input type="submit">
</form>

このとき、下記のような形式で送信されます。

POST /test.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded

text1=a%26b&text2=%E3%81%82

まとめ

application/x-www-form-urlencodedはある単一のデータを表し、
multipart/form-dataは複数のコンテンツタイプをグルーピングしたデータを表す事を説明しました。

railsなどアプリケーションを作る際には、このような低レイヤーの部分が必須になることもあります。

理解できると、自分の思ったようにデータのやり取りの処理を組むことができるので、
創作の幅が広がりますよ!

– http://d.hatena.ne.jp/a666666/20110427/1303838381
– https://qiita.com/yasuhiroki/items/a569d3371a66e365316f
– https://www.wagavulin.jp/entry/2015/10/18/060938