Как отправить файл изнутри?
Формат называется multipart/form-data
, как указано по адресу: Что означает enctype = 'multipart / form-data'?
Я собираюсь:
- добавить еще ссылки на HTML5
- объяснить почему он прав с формой, отправьте пример
HTML5 ссылки
Существует три варианта для enctype
:
Как генерировать примеры
Когда вы видите пример каждого метода, становится очевидным, как он работает, и когда вам следует использовать каждый из них.
Вы можете привести примеры, используя:
Сохраните форму в минимальном .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=---------------------------9051914041544843365972754266
устанавливает тип содержимого на multipart/form-data
и говорит, что поля разделены заданной строкой boundary
.
каждое поле получает несколько подзаголовков перед своими данными: Content-Disposition: form-data;
, поле name
, filename
, за которыми следуют данные.
Сервер считывает данные до следующей строки границы. Браузер должен выбрать границу, которая не будет отображаться ни в одном из полей, поэтому эта граница может варьироваться между запросами.
Поскольку у нас есть уникальная граница, кодирование данных не требуется: двоичные данные отправляются как есть.
TODO: каков оптимальный размер границы (log(N)
бьюсь об заклад) и имя / время выполнения алгоритма, который его находит? На вопрос: https://cs.stackexchange.com/questions/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequences
Content-Type
автоматически определяется браузером.
Как именно это определяется, было задано по адресу: Как браузер определяет тип mime загруженного файла?
* * +1136 применение / х-WWW-форм-urlencoded * * 1 137
Теперь измените 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
: имеет одну байтовую границу для каждого поля (&
), но добавляет линейный коэффициент издержек 3x для каждого непечатаемого символа.
Поэтому, даже если бы мы могли отправлять файлы с application/x-www-form-urlencoded
, мы бы этого не хотели, потому что это так неэффективно.
Но для печатаемых символов, найденных в текстовых полях, это не имеет значения и создает меньше накладных расходов, поэтому мы просто используем их.