В HTTP есть два способа POST-данных: application/x-www-form-urlencoded
и multipart/form-data
. Я понимаю, что большинство браузеров могут загружать файлы, только если они multipart/form-data
используются. Существуют ли какие-либо дополнительные указания, когда следует использовать один из типов кодирования в контексте API (без использования браузера)? Например, это может быть основано на:
- размер данных
- существование не-ASCII символов
- существование на (некодированных) двоичных данных
- необходимость передавать дополнительные данные (например, имя файла)
В основном я не нашел никаких официальных указаний относительно использования различных типов контента.
http
post
http-headers
Максимум
источник
источник
Ответы:
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
Согласно спецификации :
Это означает, что для каждого не алфавитно-цифрового байта, который существует в одном из наших значений, для его представления потребуется три байта. Для больших двоичных файлов утроение полезной нагрузки будет крайне неэффективным.
Вот тут-то и
multipart/form-data
приходит. При таком способе передачи пар имя / значение каждая пара представляется как «часть» в сообщении MIME (как описано в других ответах). Части разделены определенной границей строки (выбранной специально, чтобы эта строка границы не встречалась ни в одной из полезных нагрузок "value"). Каждая часть имеет свой собственный набор заголовков MIMEContent-Type
, в частностиContent-Disposition
, который может дать каждой части свое «имя». Часть значения каждой пары имя / значение является полезной нагрузкой каждой части сообщения MIME. Спецификация MIME дает нам больше возможностей при представлении значения полезной нагрузки - мы можем выбрать более эффективное кодирование двоичных данных для экономии полосы пропускания (например, base 64 или даже необработанный двоичный файл).Почему бы не использовать
multipart/form-data
все время? Для коротких буквенно-цифровых значений (как и для большинства веб-форм) затраты на добавление всех заголовков MIME значительно перевесят любую экономию от более эффективного двоичного кодирования.источник
ЧИТАЙТЕ МЕНЬШЕ ПЕРВЫЙ ПАРА ЗДЕСЬ!
Я знаю, что это на 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 формирует документыНапример, использовать «blob» в качестве границы при отправке двоичных данных - не очень хорошо. Однако что-то вроде "! Blob!" никогда не появится вbase64
выводе.источник
index === -1
.'()+-./:=
тогда. Но случайная генерация с подстрокой проверки еще путь , и это можно сделать с помощью одной строки:while(true){r = rand(); if(data.indexOf(r) === -1){doStuff();break;}}
. Предложение EML (преобразовать в base64 просто для избежания совпадения подстрок) просто странно, не говоря уже о том, что оно приводит к ненужному снижению производительности. И все это напрасно, так как однострочный алгоритм одинаково прост и прост. Base64 не предназначен для использования (ab) таким образом, поскольку тело HTTP принимает все 8-битные октеты.Я не думаю, что HTTP ограничен POST в multipart или x-www-form-urlencoded. Content-Type заголовка ортогональна метода HTTP POST (вы можете заполнить тип MIME , который подходит вам). Это также относится к типичным веб-приложениям, основанным на представлении HTML (например, полезная нагрузка json стала очень популярной для передачи полезной нагрузки для запросов ajax).
Что касается Restful API через HTTP, наиболее популярными типами контента, с которыми я сталкивался, являются application / xml и application / json.
Приложение / XML:
Применение / JSON
двоичные данные как собственный ресурс
Я бы попытался представить двоичные данные как собственный актив / ресурс. Он добавляет еще один вызов, но лучше разбирает вещи. Примеры изображений:
В следующих ресурсах вы можете просто вставить бинарный ресурс в виде ссылки:
источник
Я согласен со многим, что сказал Мануэль. На самом деле, его комментарии относятся к этому URL ...
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
... в котором говорится:
Тем не менее, для меня все сводится к поддержке инструмента / фреймворка.
Если вы получите четкое представление о ваших пользователях и о том, как они будут использовать ваш API, это поможет вам принять решение. Если вы сделаете загрузку файлов трудной для ваших пользователей API, они уйдут, и вы потратите много времени на их поддержку.
Вторичным по отношению к этому будет инструмент поддержки, который вы имеете для написания своего API, и насколько легко для вас приспособить один механизм загрузки к другому.
источник
Небольшая подсказка с моей стороны для загрузки данных изображения холста HTML5:
Я работаю над проектом для типографии, и у меня возникли некоторые проблемы из-за загрузки изображений на сервер из
canvas
элемента HTML5 . Я боролся, по крайней мере, час, и я не получил его, чтобы правильно сохранить изображение на моем сервере.Как только я установил
contentType
опцию моего вызова jQuery ajax,application/x-www-form-urlencoded
все прошло правильно, и данные, закодированные в base64, были правильно интерпретированы и успешно сохранены в виде изображения.Может быть, это кому-то помогает!
источник
Если вам нужно использовать Content-Type = x-www-urlencoded-form, тогда НЕ используйте FormDataCollection в качестве параметра: в asp.net Core 2+ FormDataCollection не имеет конструкторов по умолчанию, которые требуются для Formatters. Вместо этого используйте IFormCollection:
источник