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

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

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

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

TL; DR

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


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

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

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

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

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

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

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

Почему бы не использовать 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 имеет никакого значения в любой загрузке файла, двоичном или другом. Если вы не правильно выбрали свою границу, то в конечном итоге у вас возникнет проблема, отправляете ли вы обычный текст или необработанный двоичный файл – сервер найдет границу в неположенном месте, и ваш файл будет усечен, или POST не удастся.

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

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

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

Приложение / XML:

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

Применение / JSON

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

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

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

POST /images Content-type: multipart/mixed; boundary="xxxx" ... multipart data 201 Created Location: http://imageserver.org/../foo.jpg  
POST /images Content-type: multipart/mixed; boundary="xxxx" ... multipart data 201 Created 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, тогда они уйдут, и вы потратите много времени на их поддержку.

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

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

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

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


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

  • HTTP POST с использованием JSON в Java
  • Как я могу отправить данные POST на URL-адрес с помощью QNetworkAccessManager
  • Отправьте файл через HTTP POST с помощью C #
  • Как добавить параметры в HttpURLConnection с помощью POST с помощью NameValuePair
  • Когда следует использовать метод GET или POST? В чем разница между ними?
  • Nodejs POST запрос multipart / form-data
  • Является ли моя новая графическая карта причиной моего ПК?
  • Строка POST для приложения ASP.NET Web Api - возвращает значение null
  • jQuery ajax upload с индикатором выполнения - без вспышки
  • Получение JSON Object Literal из HttpServletRequest
  • Как пропустить предварительный запрос OPTIONS в AngularJS
  • Interesting Posts

    Начальное меню Windows всплывает автоматически без меня, нажимая что-нибудь

    Удалите повторяющиеся записи, используя сценарий Bash

    Индивидуальная подсветка vim

    Чтение данных из SqlDataReader

    Открыть папку для заданного пути в Mac OS X

    Как я могу сериализовать свой class User для базы данных Firebase и исправить эту ошибку?

    Предварительный просмотр Aeropeek панели задач и автоматическое закрытие Alt-Tab в Windows 7

    std :: map значение по умолчанию для встроенного типа

    Оператор перегрузки <<: невозможно привязать lvalue к 'std :: basic_ostream &&’

    Как нарисовать пользовательскую кнопку в окне заголовка windows с помощью Windows Forms?

    Все окна на экране одновременно в Windows XP

    Реализуйте очередь, в которой push_rear (), pop_front () и get_min () – все операции с постоянным временем

    Есть ли редактор тегов ID3 ​​для iTunes на OS X?

    Ярлык для блокировки экрана

    Как скрыть приложение на панели задач Windows?

    Давайте будем гением компьютера.