В HTTP существует два способа отправки данных: application/x-www-form-urlencoded
и multipart/form-data
. Я понимаю, что большинство браузеров могут загружать файлы только при использовании multipart/form-data
. Есть ли какие-либо дополнительные указания, когда использовать один из типов кодировки в контексте API (без участия браузера)? Это может быть, например, основано на:
В основном, я не нашел в Интернете никаких официальных указаний относительно использования различных типов содержимого.
TL;DR
Резюме; если вам нужно передать двоичные (неалфавитно-цифровые) данные (или полезную нагрузку значительного размера), используйте multipart/form-data
. В противном случае используйте application/x-www-form-urlencoded
.
Упомянутые вами типы MIME - это два заголовка Content-Type
для HTTP POST запросов, которые должны поддерживать пользовательские агенты (браузеры). Целью обоих этих типов запросов является отправка на сервер списка пар имя/значение. В зависимости от типа и объема передаваемых данных, один из методов будет более эффективным, чем другой. Чтобы понять, почему, нужно посмотреть, что каждый из них делает под прикрытием.
Для application/x-www-form-urlencoded
тело HTTP-сообщения, отправляемого на сервер, по сути, является одной огромной строкой запроса - пары имя/значение разделяются амперсандом (&
), а имена отделяются от значений символом равенства (=
). Примером такого запроса может быть:
МояПеременнаяОдин=ЗначениеОдин&МояПеременнаяДва=ЗначениеДва
.
Согласно спецификации:
[Зарезервированные и] неалфавитно-цифровые символы заменяются на `%HH', знак процента и две шестнадцатеричные цифры, представляющие ASCII код символа.
Это означает, что для каждого неалфавитно-цифрового байта, который есть в одном из наших значений, потребуется три байта для его представления. Для больших двоичных файлов утроение полезной нагрузки будет крайне неэффективным.
Вот тут-то и приходит на помощь multipart/form-data
. При таком способе передачи пар имя/значение каждая пара представляется как "часть" в сообщении MIME (как описано в других ответах). Части разделяются определенной строковой границей (выбранной специально для того, чтобы эта граница не встречалась ни в одном из "значений" полезной нагрузки). Каждая часть имеет свой собственный набор MIME-заголовков, таких как Content-Type
, и особенно Content-Disposition
, которые могут дать каждой части свое "имя". Часть значения каждой пары имя/значение является полезной нагрузкой каждой части MIME-сообщения. Спецификация MIME дает нам больше возможностей при представлении полезной нагрузки значения - мы можем выбрать более эффективную кодировку двоичных данных для экономии пропускной способности (например, base 64 или даже raw binary).
Почему бы не использовать multipart/form-data
постоянно? Для коротких буквенно-цифровых значений (как в большинстве веб-форм) накладные расходы на добавление всех MIME-заголовков значительно перевесят любую экономию от более эффективного двоичного кодирования.
ПРОЧИТАЙТЕ ХОТЯ БЫ ПЕРВЫЙ ПУНКТ ЗДЕСЬ!
Я знаю, что это 3-х лет слишком поздно, но Мэтт'ы (принятый) ответ является неполным и в конечном итоге получить вас в проблему. Ключевым моментом здесь является, что если вы решите использовать multipart/данные формы
, граница должна не отображаются в файле данных, что сервер в конечном итоге получает.
Это не проблема для применение/х-www-формы-urlencoded
, потому что нет границы. х-www-формы-urlencoded
всегда может работать с двоичными данными, с помощью нехитрой уловки, поворачивая один произвольный байт в три 7-разрядных байтов. Неэффективно, но работает (и обратите внимание, что комментарий о невозможности отправки файлов, а также двоичные данные неверно; вы просто отправить его в качестве другой пары ключ/значение).
Проблема с `multipart/данные формы заключается в том, что граница сепаратора не должны присутствовать в файле данных (см. RFC 2388; раздел 5.2 также включает в себя довольно жалкое оправдание для не имеющих соответствующего агрегатного типа MIME, чтобы избежать этой проблемы).
Так, на первый взгляд, `multipart/данные формы имеет никакого значения в любом файл загрузки, бинарные или иначе. Если вы Don'т выбрать свои границы правильно, потом вы будет в итоге были проблемы, то ли вы'вновь отправляю обычный текст или необработанные двоичные - сервер найти границу в неположенном месте, и ваш файл будет усечен, или пост будет выполнена.
Ключ должен выбрать кодировку и границы такие, что выбранные границы, символы не могут появляться в кодированных выходных данных. Одно простое решение состоит в использовании в base64
(не использовать необработанные двоичные). В в base64 3 произвольные байты кодируются на четыре 7-битных символов, где выходной набор символов [а-Яа-З0-9+/=]
(т. е. набор букв и цифр, '+', '/' или '='). =
это особый случай, и может появиться только в конце кодированных выходных данных, как один =
или двойной ==
. Теперь выберите ваши границы как 7-битные ASCII-строку, которая не может появиться в кодировке base64выход. Много вариантов, которые вы видите на объем не этот тест - МДН форм [документы][3], например, вставлять "клякса" в качестве границы при отправке двоичных данных - не есть хорошо. Однако, что-то вроде " у!клякса!&я никогда не появятся в кодировке base64
выход.
Я'не думаю, что HTTP ограничен POST в формате multipart или x-www-form-urlencoded. Заголовок Content-Type Header ортогонален к методу HTTP POST (вы можете заполнить MIME-тип, который вам подходит). Это также характерно для типичных веб-приложений, основанных на HTML-представлении (например, json payload стал очень популярным для передачи полезной нагрузки для ajax-запросов).
Что касается Restful API через HTTP, то наиболее популярные типы содержимого, с которыми я сталкивался, это application/xml и application/json.
Я бы попробовал представить двоичные данные как собственный актив/ресурс. Это добавляет еще один вызов, но развязывает вещи лучше. Примеры изображений:
POST /images
Content-type: multipart/mixed; boundary="xxxx"
... многочастные данные
201 Создано
Location: http://imageserver.org/../foo.jpg
В более поздних ресурсах вы можете просто вставить бинарный ресурс как ссылку:
Я согласен со многим, что сказал Мануэль. На самом деле, его комментарии относятся к этому 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, и то, насколько легко вам будет приспособить один механизм загрузки к другому.
Я работаю над проектом для печати-магазин и были некоторые проблемы из-за загрузки изображений на сервер, которые пришли из HTML5 с элемента canvas
. Я боролся в течение по крайней мере час, и я не получить его, чтобы правильно сохранить изображение на моем сервере.
Как только я поставил
значение contentType
вариант моей помощью jQuery AJAX-вызов, чтобы применение/х-www-формы-urlencoded` все шло правильно и в кодировке base64 данные были правильно истолкованы и успешно сохранен в виде изображения.
Может, это поможет кому-то!
Если вам нужно использовать тип контента=х-и www-urlencoded виде-форме, то не используйте FormDataCollection как параметр: в основной asp.net 2+ FormDataCollection не имеет конструктора по умолчанию, который требует форматирования. Использовать вместо IFormCollection:
public IActionResult Search([FromForm]IFormCollection type)
{
return Ok();
}