Jak wysyła plik wewnętrznie?
Format jest wywoływany multipart/form-data
zgodnie z pytaniem: Co oznacza enctype = 'multipart / form-data'?
Zamierzam:
- dodaj więcej odniesień do HTML5
- wyjaśnij, dlaczego ma rację, korzystając z formularza przesłania przykładu
Odnośniki HTML5
Istnieją trzy możliwości dla enctype
:
Jak wygenerować przykłady
Gdy zobaczysz przykład każdej metody, staje się oczywiste, jak działają i kiedy powinieneś użyć każdej z nich.
Możesz tworzyć przykłady, używając:
Zapisz formularz do minimalnego .html
pliku:
<!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>
Ustawiamy domyślną wartość tekstową na aωb
, co oznacza, aωb
że ω
jest U+03C9
, czyli bajtów 61 CF 89 62
w UTF-8.
Utwórz pliki do przesłania:
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
Uruchom nasz mały serwer echa:
while true; do printf '' | nc -l 8000 localhost; done
Otwórz HTML w przeglądarce, wybierz pliki, kliknij prześlij i sprawdź terminal.
nc
drukuje otrzymane żądanie.
Testowane na: Ubuntu 14.04.3, nc
BSD 1.105, Firefox 40.
multipart / form-data
Firefox wysłał:
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--
W przypadku pliku binarnego i pola tekstowego bajty 61 CF 89 62
( aωb
w UTF-8) są wysyłane dosłownie. Możesz to sprawdzić za pomocą nc -l localhost 8000 | hd
, co oznacza, że bajty:
61 CF 89 62
zostały wysłane ( 61
== 'a' i 62
== 'b').
Dlatego jasne jest, że:
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
ustawia typ zawartości na multipart/form-data
i mówi, że pola są oddzielone danym boundary
ciągiem.
Pamiętaj jednak, że:
boundary=---------------------------735323031399963166993862150
ma dwa mniej ojców --
niż rzeczywista bariera
-----------------------------735323031399963166993862150
Wynika to z faktu, że norma wymaga, aby granica zaczynała się od dwóch myślników --
. Inne myślniki wydają się być tym, w jaki sposób Firefox wybrał implementację arbitralnej granicy. RFC 7578 wyraźnie wspomina, że te dwa wiodące myślniki --
są wymagane:
4.1 „Boundary” Parametr danych wieloczęściowych / formularzy
Podobnie jak w przypadku innych typów wieloczęściowych, części są rozdzielane ogranicznikiem granicy, konstruowanym przy użyciu CRLF, „-” i wartości parametru „granicy”.
Każde pole dostaje kilka nagłówków podrzędnych przed jego danych: Content-Disposition: form-data;
pole name
, tym filename
, po której następuje danych.
Serwer odczytuje dane do następnego ciągu granicznego. Przeglądarka musi wybrać granicę, która nie pojawi się w żadnym z pól, dlatego granica może się różnić w zależności od żądania.
Ponieważ mamy unikalną granicę, kodowanie danych nie jest konieczne: dane binarne są wysyłane w niezmienionej postaci.
DO ZROBIENIA: jaki jest optymalny rozmiar granicy ( log(N)
założę się) i nazwa / czas działania algorytmu, który ją znajduje? Pytanie zadane na: /cs/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequences
Content-Type
jest automatycznie określany przez przeglądarkę.
Jak to dokładnie ustalić, zapytano na stronie: W jaki sposób typ MIME przesłanego pliku jest określany przez przeglądarkę?
application / x-www-form-urlencoded
Teraz zmienić enctype
się application/x-www-form-urlencoded
, załaduj przeglądarkę, i ponownie.
Firefox wysłał:
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
Najwyraźniej dane pliku nie zostały wysłane, tylko nazwy basename. Nie można tego użyć do plików.
Co do pola tekstowego, widzimy, że zwykłe znaki druku jak a
i b
wysłano w jednym bajcie, a niedrukowalne te, jak 0xCF
i 0x89
zajął 3 bajty każda: %CF%89
!
Porównanie
Przesyłane pliki często zawierają wiele znaków niedrukowalnych (np. Obrazy), podczas gdy formularze tekstowe prawie nigdy tego nie robią.
Z przykładów, które widzieliśmy, że:
multipart/form-data
: dodaje do wiadomości kilka bajtów narzutu granicznego i musi poświęcić trochę czasu na jego obliczenie, ale wysyła każdy bajt w jednym bajcie.
application/x-www-form-urlencoded
: ma granicę jednego bajtu na pole ( &
), ale dodaje liniowy współczynnik obciążenia 3x dla każdego znaku, który nie może być wydrukowany.
Dlatego nawet gdybyśmy mogli przesyłać pliki application/x-www-form-urlencoded
, nie chcielibyśmy, ponieważ jest to tak nieefektywne.
Ale w przypadku znaków drukowalnych znalezionych w polach tekstowych nie ma to znaczenia i generuje mniejszy narzut, więc po prostu go używamy.