application / x-www-form-urlencoded или multipart / form-data? - PullRequest
1221 голосов
/ 24 октября 2010

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

  • размер данных
  • существование не-ASCII символов
  • существование на (некодированных) двоичных данных
  • необходимость передавать дополнительные данные (например, имя файла)

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

Ответы [ 6 ]

1862 голосов
/ 02 ноября 2010

TL; DR

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


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

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

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

Согласно спецификации :

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

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

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

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

129 голосов
/ 18 апреля 2014

ПРОЧИТАЙТЕ КАК ПЕРВЫЙ ПАРА ЗДЕСЬ!

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

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

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

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

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

87 голосов
/ 24 октября 2010

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

Что касается Restful API через HTTP, наиболее популярными типами контента, с которыми я сталкивался, являются приложения/ xml и application / json.

application / xml:

  • размер данных: XML очень многословен, но обычно не представляет проблемы при использовании сжатия и думает, что случай доступа для записи (например, через POST или PUT) гораздо реже, чем доступ для чтения (во многих случаях это <3% от всего трафика).Редко в тех случаях, когда мне приходилось оптимизировать производительность записи </li>
  • существование не-ascii символов: вы можете использовать utf-8 в качестве кодировки в XML
  • существование двоичных данных: необходимо использоватькодировка base64
  • данных имени файла: вы можете инкапсулировать это внутреннее поле в XML

application / json

  • размер данных: более компактный, чем XML,текст, но вы можете сжать
  • не-ascii символов: json is 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&gt
 ...
 <link href="http://imageserver.org/../foo.jpg"/>
</main-resource>
29 голосов
/ 27 октября 2010

Я согласен со многим, что сказал Мануэль. На самом деле, его комментарии относятся к этому 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, и насколько легко для вас приспособить один механизм загрузки к другому.

2 голосов
/ 10 декабря 2015

Совсем немного с моей стороны для загрузки данных изображения холста HTML5:

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

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


Может быть, это кому-нибудь поможет!

1 голос
/ 02 октября 2018

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

 public IActionResult Search([FromForm]IFormCollection type)
    {
        return Ok();
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...