application/x-www-form-urlencoded или multipart / form-data?

в HTTP есть два способа опубликовать данные:application/x-www-form-urlencoded и multipart/form-data. Я понимаю, что большинство браузеров могут загружать файлы только если есть. Есть ли какие-либо дополнительные рекомендации по использованию одного из типов кодировки в контексте API (без браузера)? Это может быть, например, основано на:

  • размер данных
  • существование символов, отличных от ASCII
  • существование на (unencoded) двоичных данных
  • необходимость передачи дополнительных данных (например, filename)

Я в основном не нашел официального руководства в интернете относительно использования различных типов контента до сих пор.

6 ответов


TL; DR

сводка; если у вас есть двоичные (не буквенно-цифровые) данные (или полезная нагрузка значительного размера) для передачи, используйте multipart/form-data. В противном случае, используйте application/x-www-form-urlencoded.


типы MIME, вы упоминаете два Content-Type заголовки для запросов HTTP POST, которые должны поддерживать пользовательские агенты (браузеры). Целью обоих этих типов запросов является отправка на сервер списка пар имя / значение. В зависимости от типа и объема данных передается, один из методов будет более эффективным, чем другой. Чтобы понять, почему, вы должны посмотреть, что каждый делает под одеялом.

на application/x-www-form-urlencoded, тело HTTP-сообщения, отправленного на сервер, по существу является одной гигантской строкой запроса - пары имя / значение разделены амперсандом (&), а имена отделяются от значений символом equals (=). Примером этого может служить:

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

по спецификация:

[зарезервированные и] не буквенно-цифровые символы заменяются на "%HH", знак процента и две шестнадцатеричные цифры, представляющие код ASCII символа

это означает, что для каждого не буквенно-цифрового байта, который существует в одном из наших значений, для его представления потребуется три байта. Для больших двоичных файлов утроение полезной нагрузки будет крайне неэффективным.

вот тут multipart/form-data войти. С помощью этого метода передачи пар имя / значение каждая пара представлена как" часть " в сообщении MIME (как описано в других ответах). Части разделяются определенной Строковой границей (выбранной специально так, чтобы эта граничная строка не встречалась ни в одной из полезных нагрузок "значение"). Каждая часть имеет свой собственный набор заголовков MIME, как Content-Type и особенно Content-Disposition, который может дать каждой части свое "имя."Часть значения каждой пары имя / значение является полезной нагрузкой каждой части сообщение MIME. Спецификация MIME дает нам больше возможностей при представлении полезной нагрузки значения - мы можем выбрать более эффективное кодирование двоичных данных для сохранения полосы пропускания (например, base 64 или даже raw binary).

почему бы не использовать multipart/form-data все время? Для коротких буквенно-цифровых значений (как и большинство веб-форм) накладные расходы на добавление всех заголовков MIME значительно перевешивают любую экономию от более эффективного двоичного кодирования.


ПРОЧИТАЙТЕ ХОТЯ БЫ ПЕРВЫЙ ПАРАГРАФ ЗДЕСЬ!

Я знаю, что это 3 года слишком поздно, но (принятый) ответ Мэтта неполон и в конечном итоге приведет вас к неприятностям. Ключ здесь в том, что, если вы решите использовать multipart/form-data, границы должны не отображаются в файле данных, которые сервер в конечном итоге получает.

это не проблема для application/x-www-form-urlencoded, потому что нет границы. x-www-form-urlencoded может также всегда обрабатывать двоичные данные, простым целесообразность превращения одного произвольного байта в три 7BIT байт. Неэффективно, но это работает (и обратите внимание, что комментарий о невозможности отправки имен файлов, а также двоичных данных неверен; вы просто отправляете его как другую пару ключ/значение).

проблема с multipart/form-data заключается в том, что разделитель границ не должен присутствовать в данных файла (см. RFC2388; раздел 5.2 также включает довольно хромое оправдание отсутствия надлежащего агрегатного типа MIME, который позволяет избежать этого проблема.)

так, на первый взгляд, multipart/form-data не имеет никакого значения в любой загрузка файлов, двоичных или других. Если вы неправильно выбираете границу, то вы будет в конце концов, есть проблема, отправляете ли вы обычный текст или необработанный двоичный файл - сервер найдет границу в неправильном месте, и ваш файл будет усечен, или сообщение потерпит неудачу.

ключ должен выбрать кодировку и границу, чтобы выбранный вами граничные символы не могут отображаться в закодированном выводе. Одно простое решение-использовать base64 (do не используйте RAW binary). В в base64 3 произвольных байта кодируются в четыре 7-битных символа, где выходной набор символов [A-Za-z0-9+/=] (т. е. буквенно-цифровые, или '+', '/', '='). = является частным случаем и может отображаться только в конце закодированного вывода, Как один = или двойной ==. Теперь выберите границу как 7-битную строку ASCII, которая не может появиться в base64 выход. Многие варианты, которые вы видите в сети, не проходят этот тест-MDN forms docs, например, использовать "blob" в качестве границы при отправке двоичных данных - нехорошо. Однако, что-то вроде "!капля!"никогда не появится в base64 выход.


Я не думаю, что HTTP ограничен публикацией в multipart или x-www-form-urlencoded. The Заголовок Типа Контента ортогонально методу HTTP POST (вы можете заполнить тип MIME, который вам подходит). Это также относится к типичным веб-приложениям на основе представления HTML (например, полезная нагрузка json стала очень популярной для передачи полезной нагрузки для запросов ajax).

относительно Restful API через HTTP самые популярные типы контента, с которыми я связался, - это application / xml и application / json.

application / xml:

  • размер данных: XML очень подробный, но обычно не проблема при использовании сжатия и думать, что случай доступа для записи (например, через POST или PUT) гораздо реже, чем доступ для чтения (во многих случаях это
  • существование символов, отличных от ascii: вы можете использовать utf-8 в качестве кодировки в XML
  • существования бинарных данные: нужно будет использовать кодировку base64
  • filename data: вы можете инкапсулировать это внутреннее поле в XML

application / json

  • размер данных: более компактный меньше, чем XML, еще текст, но вы можете сжать
  • non-ascii chars: json-utf-8
  • двоичные данные: base64 (Также см. JSON-binary-вопрос)
  • filename data: инкапсулировать как собственное поле-раздел внутри в JSON

двоичные данные как собственный ресурс

Я бы попытался представить двоичные данные как собственный актив / ресурс. Он добавляет еще один вызов, но развязывает материал лучше. Пример изображения:

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

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

в более поздних ресурсах вы можете просто встроить двоичный ресурс как ссылку:

<main-resource&gt
 ...
 <link href="http://imageserver.org/../foo.jpg"/>
</main-resource>

Я согласен со многим, что сказал Мануэль. Фактически, его комментарии ссылаются на этот url...

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

... который гласит:

тип содержимого "application/x-www-form-urlencoded" is неэффективно для отправки больших количество двоичных данных или текста содержит символы, отличные от ASCII. Этот тип контента " multipart / form-data" следует использовать для подачи форм что содержат файлы, не-ASCII данные, и двоичные данные.

однако для меня это сводится к поддержке инструмента / фреймворка.

  • какие инструменты и механизмы вы ожидайте, что пользователи API будут создавать их приложения?
  • у них есть рамки или компоненты, которые они могут использовать что за один способ за другие?

Если вы получите четкое представление о своих пользователях и о том, как они будут использовать ваш API, это поможет вам решать. Если вы затрудните загрузку файлов для пользователей API, они уйдут, и вы потратите много времени на их поддержку.

вторичным для этого будет поддержка инструмента, который у вас есть для написания вашего API, и как легко вам разместить один механизм загрузки над другим.


просто небольшой намек с моей стороны для загрузки данных HTML5 canvas image:

Я работаю над проектом для типографии и имел некоторые проблемы из-за загрузки изображений на сервер, который пришел из HTML5 canvas элемент. Я боролся по крайней мере час, и я не получил его, чтобы сохранить изображение правильно на моем сервере.

как только я установлю contentType опция моего вызова jQuery ajax в application/x-www-form-urlencoded все прошло правильно, и данные, закодированные в base64, были интерпретировано правильно и успешно сохранено как изображение.


может быть, это кому-то помогает!


Если вам нужно использовать Content-Type=x-www-urlencoded-form, то не используйте FormDataCollection в качестве параметра: In asp.net Core 2 + FormDataCollection не имеет конструкторов по умолчанию, которые требуются Форматерам. Вместо этого используйте IFormCollection:

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