application/x-www-form-urlencoded or multipart/form-data?

HTTPにはデータをPOSTする方法が2つあります。それは application/x-www-form-urlencodedmultipart/form-data です。ほとんどのブラウザは、multipart/form-dataを使用した場合にのみ、ファイルをアップロードすることができると理解しています。APIのコンテキスト(ブラウザが関与しない)で、エンコーディングタイプのいずれかを使用する場合の追加ガイダンスはありますか?例えば、以下のようなことが考えられます。

  • データサイズ
  • 非ASCII文字の存在
  • (エンコードされていない)バイナリデータの存在
  • 追加データ(ファイル名など)を転送する必要があるかどうか

これまでのところ、異なるコンテントタイプの使用に関する正式なガイダンスはウェブ上にありません。

ソリューション

TL;DR

まとめ; バイナリ(英数字以外)のデータ(またはかなりのサイズのペイロード)を送信する場合は、multipart/form-dataを使用してください。それ以外の場合は、application/x-www-form-urlencodedを使用してください。


あなたがおっしゃるMIMEタイプとは、ユーザーエージェント(ブラウザ)がサポートしなければならないHTTP POSTリクエストの2つのContent-Typeヘッダーのことです。 これらのタイプのリクエストの目的は、名前と値のペアのリストをサーバーに送信することです。 送信されるデータの種類と量に応じて、いずれかの方法が他の方法よりも効率的になります。 その理由を理解するには、それぞれが水面下で何をしているかを見る必要があります。

application/x-www-form-urlencodedでは、サーバーに送信されるHTTPメッセージの本文は、基本的に1つの巨大なクエリ文字列です。名前と値のペアはアンパサンド(&)で区切られ、名前と値はイコールシンボル(=`)で区切られます。 例えば、次のような例があります:  

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo`。

仕様書](http://www.w3.org/TR/html401/interact/forms.html)によると、このようになります

\Reserved and\」の英数字以外の文字は、パーセント記号とその文字のASCIIコードを表す2桁の16進数である「%HH」に置き換えられます。

つまり、値の中に存在する英数字以外のバイト1つにつき、それを表現するために3バイトが必要になるということです。 大きなバイナリファイルの場合、ペイロードを3倍にすることは非常に効率が悪くなります。

そこで、multipart/form-dataの出番です。 名前と値のペアを送信するこの方法では、各ペアはMIMEメッセージの「パート」として表現されます(他の回答で説明されています)。 パートは、特定の文字列の境界で区切られています(この境界文字列が「値」のペイロードのどれにも現れないように、特に選択されています)。 各パートは、Content-Typeや、特にContent-Dispositionなどの独自のMIMEヘッダのセットを持ち、各パートに "名前 "を与えることができます。 各名前/値のペアの値の部分は、MIMEメッセージの各パートのペイロードです。 MIME仕様では、値のペイロードを表現する際に、より多くのオプションが用意されています。バンド幅を節約するために、より効率的なバイナリデータのエンコーディングを選択することができます(たとえば、ベース64や生のバイナリなど)。

なぜ multipart/form-data を常に使用しないのですか? ほとんどのウェブフォームのような短い英数字の場合、すべての MIME ヘッダーを追加することによるオーバーヘッドは、より効率的なバイナリエンコーディングによる節約を大幅に上回るでしょう。

解説 (16)

HTTPはmultipartやx-ww-form-urlencodedでのPOSTに限らないと思います。Content-Type Header][1]は、HTTPのPOSTメソッドとは直交しています(自分に合ったMIMEタイプを記入できます)。これは、典型的なHTML表現ベースのウェブアプリケーションの場合も同様です(例えば、ajaxリクエストのペイロードを送信するためにjsonペイロードが非常に普及しました)。

HTTP上のRestful APIに関して、私が接した最も一般的なコンテンツタイプは、application/xmlとapplication/jsonでした。

application/xmlです。

  • data-size:XMLは非常に冗長ですが、圧縮を使用し、書き込みアクセス(POSTやPUTなど)は読み取りアクセスよりもはるかに稀であると考えれば、通常は問題になりません(多くの場合、全トラフィックの3%未満です)。書き込みのパフォーマンスを最適化しなければならないケースはほとんどありませんでした。
  • 非アスキー文字の存在:XMLのエンコーディングとしてutf-8を使用することができます。
  • バイナリデータの存在: base64エンコーディングを使用する必要があります。
  • ファイル名データ:XMLのフィールド内にカプセル化することができる

application/json

  • データサイズ: XMLよりもコンパクトで、テキストであることに変わりはないが、圧縮することができる
  • アスキー文字以外の文字:jsonはutf-8です。
  • バイナリデータ:base64([json-binary-question][2]も参照してください。
  • ファイル名データ: json内のフィールドセクションとしてカプセル化する

バイナリデータのリソース化

バイナリデータを独自のアセット/リソースとして表現することを試みます。呼び出し回数は増えますが、分離がうまくいきます。画像の例です。

POST /images
Content-type: multipart/mixed; boundary="xxxx"
... マルチパートデータ

201 作成 Location: http://imageserver.org/../foo.jpg

それ以降のリソースでは、単純にバイナリリソースをリンクとしてインライン化することができます。

解説 (3)

私はManuel氏の発言の多くに同意します。実際、彼のコメントはこのURLを参照しています...

http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4

...以下のように書かれています。

コンテンツタイプ application/x-www-form-urlencoded "というコンテンツタイプは 大量のバイナリデータやテキストを送信するには非効率的です。 大量のバイナリデータや非ASCII文字を含むテキストを 非ASCII文字を含むテキストを大量に送信するには非効率的です。コンテンツタイプが コンテントタイプ「multipart/form-data」は ファイルや非ASCIIデータを含むフォームを送信する際には ファイル、非ASCIIデータ、バイナリデータを含むフォームの送信には およびバイナリデータを含むフォームを送信する際に使用してください。

しかし、私にとっては、ツールやフレームワークのサポートに帰結します。

  • APIユーザーがどのようなツールやフレームワークを使って どんなツールやフレームワークを使って アプリを構築することを想定していますか?
  • ユーザーが使用できる 使えるフレームワークやコンポーネントで フレームワークやコンポーネントで していますか?

ユーザーのことを明確に把握し、彼らがどのようにAPIを利用するのかを知ることができれば、それが判断の助けになります。APIユーザーにとってファイルのアップロードが困難であれば、ユーザーは離れていくでしょうし、サポートに多くの時間を費やすことになるでしょう。

そのためには、あなたがAPIを作成する際にどのようなツールをサポートしているか、また、あるアップロード・メカニズムを他のメカニズムに比べてどれだけ簡単に対応できるかが重要になります。

解説 (2)