Odpowiedzi:
Kiedy składasz żądanie POST, musisz w pewien sposób zakodować dane, które składają się na treść żądania.
Formularze HTML zapewniają trzy metody kodowania.
application/x-www-form-urlencoded
(domyślny)multipart/form-data
text/plain
Trwają prace nad dodaniem application/json
, ale zostało to porzucone.
(Możliwe są inne kodowania w przypadku żądań HTTP generowanych przy użyciu innych środków niż przesyłanie formularza HTML. JSON jest popularnym formatem do użytku z usługami internetowymi, a niektóre nadal używają SOAP.)
Specyfika formatów nie ma znaczenia dla większości programistów. Ważne punkty to:
text/plain
.Podczas pisania kodu po stronie klienta:
multipart/form-data
gdy formularz zawiera jakiekolwiek <input type="file">
elementymultipart/form-data
lub, application/x-www-form-urlencoded
ale application/x-www-form-urlencoded
będzie bardziej wydajnyPodczas pisania kodu po stronie serwera:
Większość (jak Perl CGI->param
lub ten ujawniony przez $_POST
superglobal PHP ) zajmie się różnicami. Nie przejmuj się próbą przetworzenia nieprzetworzonych danych wejściowych otrzymanych przez serwer.
Czasami znajdziesz bibliotekę, która nie obsługuje obu formatów. Najpopularniejszą biblioteką Node.js do obsługi danych formularzy jest body-parser, który nie może obsłużyć żądań wieloczęściowych (ale ma dokumentację, która zaleca pewne alternatywy, które mogą).
Jeśli piszesz (lub debugujesz) bibliotekę do analizowania lub generowania surowych danych, musisz zacząć martwić się o format. Możesz także chcieć o tym wiedzieć ze względu na zainteresowanie.
application/x-www-form-urlencoded
jest mniej więcej taki sam jak ciąg zapytania na końcu adresu URL.
multipart/form-data
jest znacznie bardziej skomplikowany, ale pozwala na włączenie całych plików do danych. Przykład wyniku można znaleźć w specyfikacji HTML 4 .
text/plain
jest wprowadzony przez HTML 5 i jest użyteczny tylko do debugowania - ze specyfikacji : Nie są one niezawodnie interpretowalne przez komputer - i twierdzę, że inne w połączeniu z narzędziami (takimi jak Panel sieci w narzędziach programistycznych większości przeglądarek) są lepsze za to).
kiedy powinniśmy go użyć
Odpowiedź Quentina jest prawidłowa: użyj, multipart/form-data
jeśli formularz zawiera przesyłanie pliku, a w application/x-www-form-urlencoded
przeciwnym razie, co jest domyślne, jeśli pominiesz enctype
.
Zamierzam:
Istnieją trzy możliwości dla enctype
:
application/x-www-form-urlencoded
multipart/form-data
(spec wskazuje na RFC7578 )text/plain
. Nie jest to „niezawodnie interpretowalne przez komputer”, więc nigdy nie powinno się go stosować w produkcji i nie będziemy się temu zagłębiać.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:
nc -l
lub serwer ECHO: serwer testowy HTTP akceptuje żądania GET / POSTZapisz 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.
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ę?
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
!
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.
%CF
jest długa: 3 bajty %
, C
a F
:-) Historia czyni go czytelny dla człowieka.
nc
nie będzie akceptować zarówno -l
i te -p
argumenty jednocześnie. Ale to działa na mnie while true; do printf '' | nc -l 8000; done
.
Content-Type
ma dwa łączniki ( --
) mniej, tzn. Kiedy faktycznie używasz granicy w treści wiadomości, musisz ją poprzedzić --
. Ostatnią granicę należy także uzupełnić --
, ale łatwo to zauważyć. Zobacz stackoverflow.com/questions/3508252/…
enctype='multipart/form-data
jest typem kodowania, który umożliwia wysyłanie plików za pomocą POST . Po prostu bez tego kodowania pliki nie mogą być wysyłane przez POST .
Jeśli chcesz zezwolić użytkownikowi na przesyłanie pliku za pomocą formularza, musisz użyć tego typu .
multipart/form-data
do wysyłania plików niebinarnych, ale jest to nieefektywne. Wydaje mi się, że używanie application/x-www-form-urlencoded
jest poprawnym sposobem wysyłania danych niebinarnych, ale ktoś z większym doświadczeniem z plikami niebinarnymi może potrzebować mnie poprawić.
multipart/form-data
do wysyłania pliku jest to, że będzie on działał automatycznie zarówno w interfejsie użytkownika, jak i w interfejsie użytkownika. Nie musisz wykonywać żadnych specjalnych czynności. Wszystkie pliki są binarne, nawet jeśli powinny zawierać tylko tekst. application/x-www-form-urlencoded
jest standardowym sposobem POST formularza bez załączonych plików. multipart/form-data
jest standardowym sposobem POST formularza z załączonymi plikami. (Istnieje również wiele innych kodowań, takich jak application/json
i application/json-patch+json
, które są wspólne dla komunikacji między serwerem a klientem.)
multipart/form-data
. Czego nie może zrobić, to zrobić za pomocą zwykłego przesyłanie formularza HTML, bez JavaScriptu. Ustawienie formularza do użycia multipart/form-data
jest jedynym mechanizmem zapewnianym przez HTML, który umożliwia pliki POST bez użycia JavaScript. Wydaje mi się, że nie jest to wystarczająco jasne w odpowiedzi i naiwny czytelnik może pomyśleć, że niemożność przesłania plików bez multipart/form-data
ograniczeń jest ograniczeniem HTTP ; nie o to chodzi.
Przesyłając formularz, powiadamiasz przeglądarkę, aby wysłała za pośrednictwem protokołu HTTP wiadomość w sieci, odpowiednio umieszczoną w strukturze wiadomości protokołu TCP / IP. Strona HTML ma sposób na przesłanie danych do serwera: za pomocą <form>
s.
Po przesłaniu formularza tworzone jest żądanie HTTP i wysyłane do serwera, wiadomość będzie zawierać nazwy pól w formularzu i wartości wypełnione przez użytkownika. Ta transmisja może się zdarzyć z POST
lub GET
metod HTTP .
POST
mówi przeglądarce, aby zbudowała wiadomość HTTP i umieściła całą treść w treści wiadomości (bardzo przydatny sposób robienia rzeczy, bardziej bezpieczny i elastyczny).GET
prześle dane formularza w zapytaniu . Ma pewne ograniczenia dotyczące reprezentacji danych i długości.Atrybut enctype
ma sens tylko przy użyciu POST
metody. Jeśli jest określony, instruuje przeglądarkę, aby wysłała formularz, kodując jego zawartość w określony sposób. Z MDN - typ formularza :
Gdy wartością atrybutu metody jest post, kodem jest typ MIME treści, która jest używana do przesłania formularza na serwer.
application/x-www-form-urlencoded
: To jest ustawienie domyślne. Kiedy formularz jest wysyłany, wszystkie nazwy i wartości są gromadzone, a kodowanie adresu URL jest wykonywane na końcowym ciągu.multipart/form-data
: Znaki NIE są kodowane. Jest to ważne, gdy formularz ma kontrolę przesyłania plików. Chcesz wysłać plik binarny, co zapewni, że strumień bitów nie zostanie zmieniony.text/plain
: Spacje są konwertowane, ale kodowanie nie jest wykonywane.Podczas przesyłania formularzy mogą pojawić się pewne obawy dotyczące bezpieczeństwa, jak podano w RFC 7578 Sekcja 7: Wieloczęściowe dane formularza - Względy bezpieczeństwa :
Każde oprogramowanie do przetwarzania formularzy powinno traktować dane formularzy dostarczone przez użytkownika
z wrażliwością, ponieważ często zawierają informacje poufne lub umożliwiające
identyfikację użytkownika. W przeglądarkach internetowych powszechnie stosuje się funkcje automatycznego wypełniania formularzy; mogą one zostać wykorzystane do nakłonienia użytkowników do
nieświadomego wysłania poufnych informacji podczas wykonywania w inny sposób
nieszkodliwych zadań. dane wieloczęściowe / formularze nie zapewniają żadnych funkcji
sprawdzania integralności, zapewniania poufności, unikania
pomyłek użytkowników lub innych funkcji bezpieczeństwa; obawami tymi muszą się
zająć aplikacje do wypełniania formularzy i interpretacji danych.Aplikacje, które otrzymują formularze i przetwarzają je, muszą uważać, aby nie dostarczyć danych z powrotem do żądającej strony przetwarzającej formularze, która nie była przeznaczona do wysłania.
Ważne jest, aby interpretować nazwę pliku w
polu nagłówka Content- Disposition, aby nieumyślnie nadpisać pliki w obszarze plików
odbiorcy.
Dotyczy to Ciebie, jeśli jesteś programistą, a Twój serwer będzie przetwarzał formularze przesłane przez użytkowników, które mogą ostatecznie zawierać poufne informacje.
enctype
robimy. Wiem, że to dosłownie z multipart/form-data
RFC, ale mimo to jest to arbitralny zrzut względów bezpieczeństwa dotyczących przesyłania formularzy, które są całkowicie ortogonalne względem tego, czy dane są wysyłane jako application/x-www-form-urlencoded
czy multipart/form-data
.
Ustaw atrybut metody na POST, ponieważ zawartości pliku nie można umieścić w parametrze URL za pomocą formularza.
Ustaw wartość typu kodowania na wieloczęściowe / dane formularza, ponieważ dane zostaną podzielone na wiele części, po jednej dla każdego pliku plus jedna dla tekstu treści formularza, który można z nimi wysłać.
POST
to, że prawdopodobnie wystarczy przesłanie pliku za pomocą formularza, a dodanie multipart/form-data
jest jedynie premią w jakiś niejasny sposób. Nie o to chodzi. Większość plików będzie absolutnie wymagać użycia multipart/form-data
.
<head>
i <body>
jest nieistotne i mylące.
Zwykle dzieje się tak, gdy masz formularz POST, który wymaga przesłania pliku jako danych ... powie to serwerowi, w jaki sposób koduje przesyłane dane, w takim przypadku nie zostanie zakodowany, ponieważ po prostu przesyła i przesyła pliki na serwer, na przykład podczas przesyłania obrazu lub pliku pdf
Atrybut enctype określa, w jaki sposób dane formularza powinny być kodowane podczas przesyłania ich na serwer.
Atrybutu enctype można użyć tylko wtedy, gdy method = "post".
Żadne znaki nie są kodowane. Ta wartość jest wymagana, gdy używasz formularzy, które mają kontrolę przesyłania plików
Od W3Schools
multipart/form-data
. Jest to również dość niejasne; co w ogóle oznacza zdanie „Żadne znaki nie są kodowane”? -1.