Co oznacza enctype = „multipart / form-data”?

Odpowiedzi:

1570

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:

  • Nigdy nie należy używać text/plain.

Podczas pisania kodu po stronie klienta:

  • używać, multipart/form-datagdy formularz zawiera jakiekolwiek <input type="file">elementy
  • w przeciwnym razie możesz użyć multipart/form-datalub, application/x-www-form-urlencodedale application/x-www-form-urlencodedbędzie bardziej wydajny

Podczas pisania kodu po stronie serwera:

  • Użyj wstępnie napisanej biblioteki obsługi formularzy

Większość (jak Perl CGI->paramlub ten ujawniony przez $_POSTsuperglobal 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-datajest 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/plainjest 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).

Quentin
źródło
5
@Quentin Przepraszam, co będzie prawdopodobnym problemem, jeśli użyjemy wieloczęściowy dla wszystkich formularzy? z plikami i bez nich.
Webinan,
12
Nie ma to sensu w przypadku formularzy GET i zwiększa rozmiar pliku żądań.
Quentin,
@Quentin czy dane wieloczęściowe są domyślnie wysyłane jako strumień?
Growler
Czy enc w typie en coś oznacza?
Philip Rego,
1
„Formularze HTML zapewniają trzy metody odlewania ENC
Quentin,
449

kiedy powinniśmy go użyć

Odpowiedź Quentina jest prawidłowa: użyj, multipart/form-datajeśli formularz zawiera przesyłanie pliku, a w application/x-www-form-urlencodedprzeciwnym razie, co jest domyślne, jeśli pominiesz enctype.

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 .htmlpliku:

<!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&#x03C9;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&#x03C9;b, co oznacza, aωbże ωjest U+03C9, czyli bajtów 61 CF 89 62w 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, ncBSD 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ωbw 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=---------------------------735323031399963166993862150ustawia typ zawartości na multipart/form-datai mówi, że pola są oddzielone danym boundarycią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ć enctypesię 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 ai bwysłano w jednym bajcie, a niedrukowalne te, jak 0xCFi 0x89zajął 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.

Ciro Santilli
źródło
3
@ Khanna111 %CFjest długa: 3 bajty %, Ca F:-) Historia czyni go czytelny dla człowieka.
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功
6
Na OS X, ncnie będzie akceptować zarówno -li te -pargumenty jednocześnie. Ale to działa na mnie while true; do printf '' | nc -l 8000; done.
PhilipS
4
Niewielką, ale ważną kwestią, o której nie wspomniano, jest to, że granica określona w parametrze Content-Typema 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/…
Bernard
1
O ile mogę stwierdzić, celem umieszczenia JAKICHKOLWIEK Kresek na granicy jest uniemożliwienie sprawdzenia składni żądania wzrokowo. Nie używaj ich w swoich tokenach granicznych.
Dewi Morgan
1
@DewiMorgan Masz całkowitą rację. Zredagowałem post i usunąłem myślniki z ciągu granicznego.
Max
91

enctype='multipart/form-datajest 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 .

Matt Asbury
źródło
Więc ... jeśli plik nie jest plikiem binarnym, to czy możemy bez niego pracować?
Yugal Jindle
Z tego, co rozumiem, możesz używać multipart/form-datado wysyłania plików niebinarnych, ale jest to nieefektywne. Wydaje mi się, że używanie application/x-www-form-urlencodedjest poprawnym sposobem wysyłania danych niebinarnych, ale ktoś z większym doświadczeniem z plikami niebinarnymi może potrzebować mnie poprawić.
Matt Asbury
11
Główną zaletą używania multipart/form-datado 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-urlencodedjest standardowym sposobem POST formularza bez załączonych plików. multipart/form-datajest standardowym sposobem POST formularza z załączonymi plikami. (Istnieje również wiele innych kodowań, takich jak application/jsoni application/json-patch+json, które są wspólne dla komunikacji między serwerem a klientem.)
Daniel Luna,
6
Warto podkreślić, że możesz zakodować obraz w formacie base64 i wysłać go jako zwykły ciąg danych.
James
3
W nawiązaniu do powyższego komentarza @ Prospero: możesz absolutnie wysyłać pliki za pomocą POST bez użycia 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-datajest 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-dataograniczeń jest ograniczeniem HTTP ; nie o to chodzi.
Mark Amery
81

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 POSTlub 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).
  • GETprześle dane formularza w zapytaniu . Ma pewne ograniczenia dotyczące reprezentacji danych i długości.

Wskazując, jak wysłać formularz na serwer

Atrybut enctypema sens tylko przy użyciu POSTmetody. 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.

Bezpieczeństwo

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.

Andry
źródło
1
Rzeczy dotyczące bezpieczeństwa po ostatniej edycji nie mają znaczenia dla pytania o to, co enctyperobimy. Wiem, że to dosłownie z multipart/form-dataRFC, 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-urlencodedczy multipart/form-data.
Mark Amery
38

enctype='multipart/form-data'oznacza, że ​​żadne znaki nie będą kodowane. dlatego ten typ jest używany podczas przesyłania plików na serwer. Jest
więc multipart/form-dataużywany, gdy formularz wymaga przesłania danych binarnych, takich jak zawartość pliku

GP Singh
źródło
8

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ć.

piaszczysty
źródło
Oznacza POSTto, że prawdopodobnie wystarczy przesłanie pliku za pomocą formularza, a dodanie multipart/form-datajest jedynie premią w jakiś niejasny sposób. Nie o to chodzi. Większość plików będzie absolutnie wymagać użycia multipart/form-data.
underscore_d
1
  • Atrybut enctype ( ENC ode TYPE ) określa, w jaki sposób dane formularza powinny być kodowane podczas przesyłania ich na serwer.
  • multipart / form-data jest jedną z wartości atrybutu enctype, który jest używany w elemencie formularza, który ma załadowany plik. wieloczęściowy oznacza, że ​​dane formularza dzielą się na wiele części i wysyłają na serwer.
Premraj
źródło
5
Wierzę enctype nie stoi na typ szyfrowania. Na tym poziomie nie występuje szyfrowanie. Domyślam się, że jest to typ kodowania lub typ zamknięty. Ale na pewno nie jest to typ szyfrowania.
Yeo
1
Twój ostateczny podpunkt tutaj o <head>i <body>jest nieistotne i mylące.
Mark Amery
0

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

Eric
źródło
-3

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

Riszad
źródło
2
Ten cytat nawet nie wspomina multipart/form-data. Jest to również dość niejasne; co w ogóle oznacza zdanie „Żadne znaki nie są kodowane”? -1.
Mark Amery