Як він надсилає файл внутрішньо?
Формат називається 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=---------------------------735323031399963166993862150
встановлює тип вмісту multipart/form-data
та каже, що поля розділені заданим boundary
рядком.
Але зауважте, що:
boundary=---------------------------735323031399963166993862150
має два менші тири, --
ніж фактичний бар'єр
-----------------------------735323031399963166993862150
Це тому, що стандарт вимагає, щоб межа починалася з двох тире --
. Інші тире виглядають лише як Firefox вирішив реалізувати довільну межу. RFC 7578 чітко зазначає, що --
потрібні ці два провідні тире :
4.1. Параметр "Межі" багаточастинкових / форм-даних
Як і у інших типів з кількома частинами, деталі розмежовані граничним роздільником, побудованим за допомогою CRLF, "-" та значення параметра "межа".
кожне поле отримує деякі підзаголовки перед своїми даними:, Content-Disposition: form-data;
поле name
, the filename
, за якими йдуть дані.
Сервер зчитує дані до наступного граничного рядка. Веб-переглядач повинен вибрати межу, яка не відображатиметься в жодному з полів, тому межа може залежати від запитів.
Оскільки у нас є унікальна межа, кодування даних не потрібно: двійкові дані надсилаються як є.
TODO: який оптимальний розмір межі ( log(N)
я ставлю ставку) та ім'я / час виконання алгоритму, який його знаходить? На запитання: /cs/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequences
Content-Type
автоматично визначається браузером.
Як саме це визначено, запитували на: Як визначається браузер браузером типу mime завантаженого файлу?
додаток / x-www-form-urlencoded
Тепер змініть 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
, ми б не хотіли цього, бо це настільки неефективно.
Але для друкованих символів, знайдених у текстових полях, це не має значення і створює менше накладних витрат, тому ми просто використовуємо це.