Ответы:
Когда вы делаете запрос POST, вы должны каким-то образом кодировать данные, которые формируют тело запроса.
HTML-формы предоставляют три метода кодирования.
application/x-www-form-urlencoded
(по умолчанию)multipart/form-data
text/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-urlencoded
multipart/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, nc
BSD 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
, мы бы этого не хотели, потому что это так неэффективно.
Но для печатных символов, найденных в текстовых полях, это не имеет значения и создает меньше накладных расходов, поэтому мы просто используем их.
%CF
3 байта длиной: %
, 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-data
RFC, но, тем не менее, это произвольный дамп соображений безопасности при отправке форм, которые полностью ортогональны тому, отправляются ли данные как 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.