web-dev-qa-db-ja.com

application/x-www-form-urlencodedまたはmultipart/form-dataのどちらですか。

HTTPでは、POST dataにはapplication/x-www-form-urlencodedmultipart/form-dataの2つの方法があります。私は、multipart/form-dataが使用されている場合に限り、ほとんどのブラウザがファイルをアップロードできることを理解しています。 APIコンテキストでエンコーディングタイプの1つを使用する場合(ブラウザは関係ありません)、追加のガイダンスはありますか?これは例えばかもしれないに基づいている:

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

私は基本的に、これまでのところ、さまざまなコンテンツタイプの使用に関するWeb上の正式なガイダンスを見つけませんでした。

1201
max

TL; DR

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


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

application/x-www-form-urlencodedの場合、サーバーに送信されるHTTPメッセージの本文は基本的に1つの巨大なクエリ文字列です。名前と値のペアはアンパサンド(&)で区切られ、名前は値と等号(=)で区切られます。この例は次のようになります。

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

specification によると:

[予約および]英数字以外の文字は、パーセント記号とその文字のASCIIコードを表す2桁の16進数である `%HH 'に置き換えられます。

つまり、いずれかの値に含まれる英数字以外のバイトごとに、それを表すのに3バイトかかります。大きなバイナリファイルの場合、ペイロードを3倍にすることは非常に非効率的です。

それがmultipart/form-dataが登場するところです。名前/値のペアを送信するこの方法では、各ペアはMIMEメッセージの「一部」として表現されます(他の回答で説明されているように)。部分は特定の文字列境界で区切られています(この境界文字列がどの "値"ペイロードにも含まれないように特別に選択されています)。それぞれの部分にはContent-Type、特にContent-Dispositionのような独自のMIMEヘッダーのセットがあり、それぞれの部分に「名前」を付けることができます。各名前/値ペアの値部分は、MIMEメッセージの各部分のペイロードです。 MIME仕様は、ペイロード値を表すときにより多くのオプションを提供します。帯域幅を節約するために、バイナリデータのより効率的なエンコードを選択できます(例:base 64またはrawバイナリ)。

なぜmultipart/form-dataをずっと使わないのですか?短い英数字値(ほとんどのWebフォームと同様)では、すべてのMIMEヘッダーを追加することによるオーバーヘッドが、より効率的なバイナリエンコードによる節約よりも大幅に優先されます。

1833
Matt Bridges

READ ATここから最初のパラを失います!

私はこれが3年遅すぎることを知っていますが、Mattの(受け入れられた)答えは不完全であり、最終的にあなたをトラブルに巻き込むでしょう。ここで重要なのは、multipart/form-dataを使用することを選択した場合、サーバーが最終的に受信するファイルデータにnotが表示される必要があることです。

これはapplication/x-www-form-urlencodedの問題ではありません。境界がないためです。 x-www-form-urlencodedは、1つの任意のバイトを3つの7BITバイトに変換するという簡単な手段により、常にバイナリデータを処理することもできます。効率的ではありませんが、機能します(ファイル名やバイナリデータを送信できないことに関するコメントが間違っていることに注意してください。別のキー/値のペアとして送信するだけです)。

multipart/form-dataの問題は、境界区切り記号がファイルデータに存在してはならないことです( RFC 2388 を参照してください。セクション5.2には、適切な集約MIMEタイプがこの問題を回避します)。

したがって、一見、multipart/form-dataは、anyファイルのアップロード、バイナリなどでまったく価値がありません。境界を正しく選択しないと、プレーンテキストまたは生のバイナリを送信しているかどうかにかかわらず、最終的にに問題が発生します。サーバーは間違った境界を見つけます。ファイルを切り捨てるか、POSTが失敗します。

重要なのは、選択した境界文字がエンコードされた出力に表示されないように、エンコードと境界を選択することです。 1つの簡単な解決策は、base64を使用することです(donotrawバイナリを使用します)。 base64 では、任意の3バイトが4つの7ビット文字にエンコードされます。出力文字セットは[A-Za-z0-9+/=](つまり、英数字、 '+'、 '/'または '=')です。 =は特殊なケースであり、エンコードされた出力の最後に、シングル=またはダブル==としてのみ表示されます。ここで、base64出力に表示できない7ビットASCII文字列として境界を選択します。ネット上で見られる多くの選択肢はこのテストに失敗します-MDN形式 docs は、たとえば、バイナリデータを送信するときに境界として「blob」を使用します-良くありません。ただし、「!blob!」のようなものbase64出力には表示されません。

132
EML

私は、HTTPがマルチパートのPOSTやx-www-form-urlencodedに限定されるとは思わない。 Content-Type Header は、HTTP POSTメソッドと直交しています(自分に合ったMIMEタイプを入力できます)。これは、典型的なHTML表現ベースのWebアプリケーションの場合も同様です(例:jsonペイロードは、ajaxリクエストのペイロードを送信するために非常に一般的になりました)。

Restful API over HTTPに関して、私が連絡を取った最も人気のあるコンテンツタイプはapplication/xmlとapplication/jsonです。

application/xml:

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

アプリケーション/ JSON

  • data-size:XMLよりもコンパクトで、静止テキストですが、圧縮できます。
  • 非ASCII文字:jsonはutf-8です
  • バイナリデータ:base64( json-binary-question も参照)
  • ファイル名データ:json内に独自のフィールドセクションとしてカプセル化する

独自のリソースとしてのバイナリデータ

バイナリデータを自分の資産/リソースとして表現しようと思います。それは別の呼び出しを追加しますが、より良いものを切り離します。サンプル画像:

POST /images
Content-type: multipart/mixed; boundary="xxxx" 
... multipart data

201 Created
Location: http://imageserver.org/../foo.jpg

後のリソースでは、バイナリリソースをリンクとしてインライン化することができます。

<main-resource>
 ...
 <link href="http://imageserver.org/../foo.jpg"/>
</main-resource>
87
manuel aldana

私はマヌエルが言ったことの多くに同意します。実際、彼のコメントはこのURLを参照しています...

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

... どの州:

コンテンツタイプ "application/x-www-form-urlencoded"は、ASCII以外の文字を含む大量のバイナリデータまたはテキストを送信するには非効率的です。コンテンツタイプ "multipart/form-data"は、ファイル、非ASCIIデータ、およびバイナリデータを含むフォームを送信するために使用する必要があります。

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

  • あなたのAPIユーザーが彼らのアプリを構築するためにどのようなツールやフレームワークを期待していますか?
  • 彼らは彼らが使用できるフレームワークやコンポーネントを持っていますか?

あなたがあなたのユーザについて、そして彼らがあなたのAPIをどのように利用するかについての明確な考えを得たなら、それはあなたが決めるのを助けるでしょう。あなたがあなたのAPIユーザにとってファイルのアップロードを困難にするならば、彼らは動かないでしょう、あなたはそれらをサポートすることに多くの時間を費やすでしょう。

これに次ぐものはあなたがあなたのAPIを書くためにあなたが持っているツールサポートとあなたが他のものの上に1つのアップロードメカニズムに対応するのがどれくらい簡単であるかであろう。

29
Martin Peck

HTML5キャンバス画像データをアップロードするための私の側からのちょっとしたヒント:

私はプリントショップのプロジェクトに取り組んでいますが、HTML5のcanvas要素から取得した画像をサーバーにアップロードすることで問題が発生しました。私は少なくとも1時間奮闘していました、そして、私はそれを私のサーバーに正しく保存することができませんでした。

私のjQuery ajax呼び出しのcontentTypeオプションをapplication/x-www-form-urlencodedに設定すると、すべてが正しく行われ、base64エンコードデータは正しく解釈され、画像として正常に保存されました。


多分それは誰かを助けます!

2
Torsten Barthel

Content-Type = x-www-urlencode-formを使用する必要がある場合は、FormDataCollectionをパラメータとして使用しないでください。asp.net Core 2+のFormDataCollectionには、フォーマッタに必要なデフォルトのコンストラクタはありません。代わりにIFormCollectionを使用してください。

 public IActionResult Search([FromForm]IFormCollection type)
    {
        return Ok();
    }
1
jahansha