Ответы:
Когда вы делаете запрос POST, вы должны каким-то образом кодировать данные, которые формируют тело запроса.
HTML-формы предоставляют три метода кодирования.
application/x-www-form-urlencoded (по умолчанию)multipart/form-datatext/plainРабота над добавлением была сделана application/json, но это было заброшено.
(Другие кодировки возможны с HTTP-запросами, сгенерированными с использованием других средств, кроме отправки HTML-форм. JSON - это распространенный формат для использования с веб-службами, а некоторые все еще используют SOAP.)
Специфика форматов не имеет значения для большинства разработчиков. Важными моментами являются:
text/plain.Когда вы пишете код на стороне клиента:
multipart/form-dataкогда ваша форма содержит какие-либо <input type="file">элементыmultipart/form-dataили, application/x-www-form-urlencodedно application/x-www-form-urlencodedбудет более эффективнымКогда вы пишете код на стороне сервера:
Большинство (например, Perl CGI->paramили тот, который выставлен $_POSTсуперглобальным PHP ) позаботятся о различиях за вас. Не пытайтесь анализировать необработанные данные, полученные сервером.
Иногда вы найдете библиотеку, которая не может обрабатывать оба формата. Наиболее популярной библиотекой Node.js для обработки данных форм является body-parser, который не может обрабатывать многокомпонентные запросы (но имеет документацию, которая рекомендует некоторые альтернативы, которые могут).
Если вы пишете (или отлаживаете) библиотеку для анализа или генерации необработанных данных, вам нужно начать беспокоиться о формате. Вы также можете узнать об этом ради интереса.
application/x-www-form-urlencoded более или менее совпадает со строкой запроса в конце URL.
multipart/form-dataзначительно сложнее, но позволяет включать в данные целые файлы. Пример результата можно найти в спецификации HTML 4 .
text/plainвведен в HTML 5 и полезен только для отладки - из спецификации : они не могут быть надежно интерпретированы компьютером - и я бы сказал, что другие в сочетании с инструментами (такими как Network Panel в инструментах разработчика большинства браузеров) лучше для этого).
когда мы должны использовать это
Ответ Квентина правильный: используйте, multipart/form-dataесли форма содержит файл для загрузки, и в application/x-www-form-urlencodedпротивном случае, который используется по умолчанию, если вы его опускаете enctype.
Я собираюсь:
Есть три возможности для enctype:
application/x-www-form-urlencodedmultipart/form-data(спецификация указывает на RFC7578 )text/plain, Это «ненадежно интерпретируется компьютером», поэтому никогда не должно использоваться в производстве, и мы не будем вдаваться в подробности.Как только вы видите пример каждого метода, становится очевидным, как они работают, и когда вы должны использовать каждый из них.
Вы можете привести примеры, используя:
nc -lили сервер ECHO: тестовый сервер HTTP, принимающий запросы GET / POSTСохраните форму в минимальный .htmlфайл:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>upload</title>
</head>
<body>
<form action="http://localhost:8000" method="post" enctype="multipart/form-data">
<p><input type="text" name="text1" value="text default">
<p><input type="text" name="text2" value="aωb">
<p><input type="file" name="file1">
<p><input type="file" name="file2">
<p><input type="file" name="file3">
<p><button type="submit">Submit</button>
</form>
</body>
</html>
Мы устанавливаем текстовое значение по умолчанию aωb, что означает, aωbпотому что ωесть U+03C9, которые являются байтами 61 CF 89 62в UTF-8.
Создайте файлы для загрузки:
echo 'Content of a.txt.' > a.txt
echo '<!DOCTYPE html><title>Content of a.html.</title>' > a.html
# Binary file containing 4 bytes: 'a', 1, 2 and 'b'.
printf 'a\xCF\x89b' > binary
Запустите наш маленький эхо-сервер:
while true; do printf '' | nc -l 8000 localhost; done
Откройте HTML в вашем браузере, выберите файлы, нажмите «Отправить» и проверьте терминал.
nc печатает полученный запрос
Проверено на: Ubuntu 14.04.3, ncBSD 1.105, Firefox 40.
Firefox отправил:
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
Content-Length: 834
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text1"
text default
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text2"
aωb
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
Content of a.txt.
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html
<!DOCTYPE html><title>Content of a.html.</title>
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file3"; filename="binary"
Content-Type: application/octet-stream
aωb
-----------------------------735323031399963166993862150--
Для двоичного файла и текстового поля байты 61 CF 89 62( aωbв UTF-8) отправляются буквально. Вы можете проверить это с помощью nc -l localhost 8000 | hd, который говорит, что байты:
61 CF 89 62
были отправлены ( 61== 'a' и 62== 'b').
Поэтому ясно, что:
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150устанавливает тип содержимого multipart/form-dataи говорит, что поля разделены заданной boundaryстрокой.
Но обратите внимание, что:
boundary=---------------------------735323031399963166993862150
имеет на два меньше черт, --чем фактический барьер
-----------------------------735323031399963166993862150
Это потому, что стандарт требует, чтобы граница начиналась с двух штрихов --. Похоже, что другие черты - это то, как Firefox решил реализовать произвольную границу. RFC 7578 четко упоминает, что эти две лидирующие черты --необходимы:
4.1. «Граничный» параметр multipart / form-data
Как и в случае других составных типов, части разделяются граничным разделителем, созданным с использованием CRLF, "-" и значения параметра "border".
каждое поле получает некоторые вложенные заголовки перед своими данными: Content-Disposition: form-data;, поле name, тем filename, за которым следуют данные.
Сервер читает данные до следующей граничной строки. Браузер должен выбрать границу, которая не будет отображаться ни в одном из полей, поэтому эта граница может варьироваться между запросами.
Поскольку у нас есть уникальная граница, кодирование данных не требуется: двоичные данные отправляются как есть.
ТОДО: каков оптимальный размер границы ( log(N)бьюсь об заклад) и название / время выполнения алгоритма, который его находит? На вопрос: /cs/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequence
Content-Type определяется автоматически браузером.
Как именно это определяется, было задано по адресу: Как браузер определяет тип mime загруженного файла?
Теперь измените enctypeк application/x-www-form-urlencoded, перезагрузите браузер и повторите.
Firefox отправил:
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: application/x-www-form-urlencoded
Content-Length: 51
text1=text+default&text2=a%CF%89b&file1=a.txt&file2=a.html&file3=binary
Ясно, что данные файла не были отправлены, только базовые имена. Так что это не может быть использовано для файлов.
Что касается текстового поля, мы видим, что обычные печатаемые символы, такие как aи bбыли отправлены в один байт, а непечатные символы, такие как 0xCFи 0x89занимают 3 байта каждый %CF%89:!
Загрузки файлов часто содержат много непечатных символов (например, изображений), в то время как текстовые формы почти никогда не делают.
Из примеров мы видели, что:
multipart/form-data: добавляет к сообщению несколько байтов служебных данных границы и должен потратить некоторое время на его вычисление, но отправляет каждый байт по одному байту.
application/x-www-form-urlencoded: имеет одну байтовую границу для каждого поля ( &), но добавляет линейный коэффициент издержек в 3 раза для каждого непечатаемого символа.
Поэтому, даже если бы мы могли отправлять файлы с помощью application/x-www-form-urlencoded, мы бы этого не хотели, потому что это так неэффективно.
Но для печатных символов, найденных в текстовых полях, это не имеет значения и создает меньше накладных расходов, поэтому мы просто используем их.
%CF3 байта длиной: %, Cи F:-) История делает его читаемым человеком.
ncне будут принимать как -lи те -pаргументы одновременно. Но это работает для меня while true; do printf '' | nc -l 8000; done.
Content-Typeимеет на два дефиса ( --) меньше, то есть при фактическом использовании границы в теле сообщения вы должны использовать префикс --. Кроме того, к последней границе должен быть добавлен суффикс --, но это достаточно легко заметить. См. Stackoverflow.com/questions/3508252/…
enctype='multipart/form-dataтип кодировки, который позволяет отправлять файлы через POST . Проще говоря, без этой кодировки файлы не могут быть отправлены через POST .
Если вы хотите разрешить пользователю загружать файл через форму, вы должны использовать этот enctype .
multipart/form-dataдля отправки недвоичных файлов, но это неэффективно. Я считаю, что использование application/x-www-form-urlencodedправильного способа отправки недвоичных данных - это, возможно, кто-то с большим опытом работы с недвоичными файлами, возможно, должен исправить меня.
multipart/form-dataдля отправки файла является то, что он будет работать автоматически как во внешнем, так и во внутреннем интерфейсе. Вам не нужно делать никакой специальной обработки. Все файлы являются двоичными, даже если они должны содержать только текст. application/x-www-form-urlencodedэто стандартный способ отправить форму без вложенных файлов. multipart/form-dataэто стандартный способ отправить форму с приложенным файлом (ами). (Существует также множество других кодировок, таких как application/jsonи application/json-patch+json, которые являются общими для связи между сервером и клиентом.)
multipart/form-data. То, что вы не можете сделать, это сделать, используя обычную отправку HTML-формы, без JavaScript. Настройка формы для использования multipart/form-data- единственный механизм, который предоставляет HTML, чтобы позволить вам POST-файлы без использования JavaScript. Я чувствую, что это не достаточно ясно в ответе, и что наивный читатель может подумать, что невозможность отправки файлов multipart/form-data- это ограничение HTTP ; это не тот случай.
При отправке формы вы указываете браузеру отправлять по протоколу HTTP сообщение в сети, надлежащим образом заключенное в структуру сообщения протокола TCP / IP. На странице HTML есть способ отправки данных на сервер: с помощью <form>s.
Когда форма отправляется, HTTP-запрос создается и отправляется на сервер, сообщение будет содержать имена полей в форме и значения, заполненные пользователем. Эта передача может происходить с помощью POSTили GET HTTP-методов .
POST говорит вашему браузеру создать HTTP-сообщение и поместить все содержимое в тело сообщения (очень полезный способ сделать что-то более безопасное и гибкое).GETотправит данные формы в строке запроса . Это имеет некоторые ограничения относительно представления данных и длины.Атрибут enctypeимеет смысл только при использовании POSTметода. Если указано, он указывает браузеру отправлять форму, кодируя ее содержимое определенным образом. От MDN - Форма энктипа :
Если значением атрибута метода является post, enctype - это тип содержимого MIME, который используется для отправки формы на сервер.
application/x-www-form-urlencoded: Это по умолчанию. Когда форма отправляется, все имена и значения собираются, и в последней строке выполняется кодировка URL .multipart/form-data: Символы НЕ кодируются. Это важно, когда форма имеет элемент управления загрузкой файлов. Вы хотите отправить двоичный файл, и это гарантирует, что поток битов не будет изменен.text/plain: Пробелы конвертируются, но кодирование больше не выполняется.При отправке форм могут возникать некоторые проблемы безопасности, как указано в Разделе 7 RFC 7578: Данные из нескольких частей - Вопросы безопасности :
Все программное обеспечение для обработки форм должно обрабатывать предоставленные пользователем данные формы
с чувствительностью, поскольку оно часто содержит конфиденциальную или личную
информацию. В веб-браузерах широко используются функции автозаполнения форм; они могут быть использованы для того, чтобы обманом заставить пользователей
неосознанно отправлять конфиденциальную информацию при выполнении
безобидных заданий. multipart / form-data не предоставляет никаких функций
для проверки целостности, обеспечения конфиденциальности, предотвращения
путаницы среди пользователей или других функций безопасности; эти проблемы должны быть
решены с помощью приложений для заполнения форм и интерпретации данных.Приложения, которые получают формы и обрабатывают их, должны быть осторожны, чтобы не возвращать данные запрашивающему сайту обработки форм, который не предназначался для отправки.
При интерпретации имени файла
поля заголовка Content- Disposition важно, чтобы случайно не перезаписать файлы в
файловом пространстве получателя.
Это касается вас, если вы разработчик, и ваш сервер будет обрабатывать формы, отправленные пользователями, которые могут в конечном итоге содержать конфиденциальную информацию.
enctypeделать. Я знаю, что это буквально из multipart/form-dataRFC, но, тем не менее, это произвольный дамп соображений безопасности при отправке форм, которые полностью ортогональны тому, отправляются ли данные как application/x-www-form-urlencodedили multipart/form-data.
enctype='multipart/form-data'означает, что никакие символы не будут закодированы. именно поэтому этот тип используется при загрузке файлов на сервер.
Так multipart/form-dataиспользуется, когда форма требует, чтобы бинарные данные, такие как содержимое файла, были загружены
Установите для атрибута метода значение POST, поскольку содержимое файла нельзя поместить в параметр URL с помощью формы.
Задайте для значения enctype значение multipart / form-data, поскольку данные будут разбиты на несколько частей, по одной для каждого файла, а также по одному для текста тела формы, которое может быть отправлено вместе с ними.
POST, вероятно, будет достаточно для отправки файла через форму, и что добавление multipart/form-dataявляется лишь бонусом в некотором расплывчатом виде. Это не тот случай. Большинство файлов абсолютно необходимо использовать multipart/form-data.
<head>и не <body>имеет значения и сбивает с толку.
Обычно это когда у вас есть форма POST, которая должна принимать файл в качестве данных ... это скажет серверу, как он будет кодировать передаваемые данные, в этом случае он не будет закодирован, потому что он будет просто передавать и загружать файлы на сервер, как, например, при загрузке изображения или PDF
Атрибут enctype указывает, как данные формы должны быть закодированы при отправке на сервер.
Атрибут enctype можно использовать, только если method = "post".
Никакие символы не закодированы. Это значение требуется при использовании форм, которые имеют элемент управления загрузкой файлов
Из W3Schools
multipart/form-data. Это также довольно неясно; что вообще означает предложение «Никакие символы не закодированы»? -1.