application/x-www-form-urlencoded czy multipart / form-data?

W HTTP są dwa sposoby zamieszczania danych: application/x-www-form-urlencoded i multipart/form-data. Rozumiem, że większość przeglądarek może przesyłać pliki tylko wtedy, gdy używana jest multipart/form-data. Czy są jakieś dodatkowe wskazówki, kiedy używać jednego z typów kodowania w kontekście API(bez przeglądarki)? Może to być np. oparte na:

  • Rozmiar danych
  • istnienie znaków nie-ASCII
  • istnienie na (niekodowanych) danych binarnych
  • potrzeba przesłania dodatkowych danych (np. nazwy pliku)

I zasadniczo nie znaleziono żadnych formalnych wskazówek w Internecie dotyczących korzystania z różnych rodzajów treści.

Author: max, 2010-10-24

6 answers

TL; DR

Podsumowanie; jeśli masz dane binarne (nie alfanumeryczne) (lub znacznie większy ładunek) do przesłania, użyj multipart/form-data. W przeciwnym razie użyj application/x-www-form-urlencoded.


Typy MIME, o których wspominasz, to dwa Content-Type nagłówki żądań HTTP POST, które muszą obsługiwać agenci użytkownika (przeglądarki). Celem obu tych typów żądań jest wysłanie listy par nazwa/wartość do serwera. W zależności od rodzaju i ilości przesyłanych danych, jedną z metod będzie bardziej wydajne niż inne. Aby zrozumieć dlaczego, trzeba spojrzeć na to, co każdy robi pod kołdrą.

Dla application/x-www-form-urlencoded, treść wiadomości HTTP wysyłanej do serwera jest zasadniczo jednym gigantycznym ciągiem zapytań -- pary nazwa / wartość są oddzielone przez ampersand (&), A nazwy są oddzielone od wartości symbolem równości (=). Przykładem tego może być:

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

Według specyfikacji :

[zastrzeżone i] znaki niealfanumeryczne są zastępowane przez "%HH", znak procentowy i dwie cyfry szesnastkowe reprezentujące kod ASCII znaku

Oznacza to, że dla każdego nie-alfanumerycznego bajtu, który istnieje w jednej z naszych wartości, reprezentowanie go zajmie trzy bajty. W przypadku dużych plików binarnych potrojenie ładunku będzie wysoce nieefektywne.

Tu wkracza multipart/form-data. Dzięki tej metodzie przekazywania par nazwa / wartość każda para jest reprezentowana jako " część" w wiadomości MIME (opisanej przez inne odpowiedzi). Części są oddzielone określoną granicą łańcucha znaków (wybraną specjalnie w taki sposób, że ten łańcuch nie występuje w żadnej z" wartości " ładunków). Każda część ma swój własny zestaw nagłówków MIME, takich jak Content-Type, a szczególnie Content-Disposition, które mogą nadać każdej części swoją " nazwę."Kawałek wartości każdej pary nazwa / wartość jest ładunkiem każdej części wiadomości MIME. Specyfikacja MIME daje nam więcej opcji podczas reprezentowania wartości payload -- możemy wybrać bardziej wydajne kodowanie danych binarnych w celu zaoszczędzenia przepustowości (np.

Dlaczego nie używać multipart/form-data cały czas? W przypadku krótkich wartości alfanumerycznych (jak w przypadku większości formularzy internetowych), nagłówki MIME znacznie przewyższają wszelkie oszczędności wynikające z bardziej wydajnego kodowania binarnego.

 1710
Author: Matt Bridges,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-28 22:42:45

PRZECZYTAJ PRZYNAJMNIEJ PIERWSZĄ PARA TUTAJ!

Wiem, że to o 3 lata za późno, ale odpowiedź Matta (zaakceptowana) jest niekompletna i w końcu wpędzi cię w kłopoty. Kluczem jest to, że jeśli zdecydujesz się użyć multipart/form-data, granica musi nie pojawiać się w danych Pliku, które serwer ostatecznie otrzymuje.

To nie jest problem dla application/x-www-form-urlencoded, ponieważ nie ma granicy. x-www-form-urlencoded może również zawsze obsługiwać dane binarne, poprzez proste obracanie jednego dowolnego bajt na trzy 7BIT bajty. Nieefektywny, ale działa (i zauważ, że komentarz o braku możliwości wysyłania nazw plików, jak również danych binarnych jest nieprawidłowy; po prostu wysyłasz go jako inną parę klucz / wartość).

Problem z multipart/form-data polega na tym, że separator boundary nie może być obecny w danych pliku (Zobacz RFC2388; sekcja 5.2 zawiera również dość kiepski pretekst do braku odpowiedniego typu MIME agregującego, który pozwala uniknąć tego problemu).

Więc na pierwszy rzut oka multipart/form-data jest nie wartość w dowolne przesyłanie plików, binarne lub inne. Jeśli nie wybierzesz poprawnie swojej granicy, wtedy W końcu będziesz miał problem, niezależnie od tego, czy wysyłasz zwykły tekst, czy surowy plik binarny - serwer znajdzie granicę w niewłaściwym miejscu, a Twój plik zostanie obcięty, lub POST zawiedzie.

Kluczem jest wybranie kodowania i granicy tak, aby wybrane znaki graniczne nie mogły pojawić się w zakodowanym wyjściu. Jednym prostym rozwiązaniem jest użycie base64 (do nie używaj raw binary). W base64 3 dowolne bajty są kodowane na cztery 7-bitowe znaki, gdzie wyjściowy zestaw znaków to [A-Za-z0-9+/=] (tj. alfanumeryczne, lub '+', '/', '='). {[8] } jest szczególnym przypadkiem i może pojawić się tylko na końcu zakodowanego wyjścia, jako pojedynczy = lub podwójny ==. Teraz wybierz granicę jako 7-bitowy ciąg ASCII, który nie może pojawić się na wyjściu base64. Wiele opcji, które widzisz w sieci, nie sprawdza się w tym teście - formularze MDN docs, dla przykład, użyj "blob" jako granicy podczas wysyłania danych binarnych-niedobrze. Jednak coś w stylu"!blob!"nigdy nie pojawi się na wyjściu base64.

 112
Author: EML,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-18 11:08:05

Myślę, że HTTP nie jest ograniczone do postu w multipart lub x-www-form-urlencoded. Nagłówek Content-Type jest ortogonalny do metody HTTP POST (możesz wypełnić typ MIME, który Ci odpowiada). Tak jest również w przypadku typowych aplikacji webowych opartych na reprezentacji HTML (np. JSON payload stał się bardzo popularny do przesyłania payload dla żądań ajax).

Jeśli chodzi o Restful API przez HTTP, najpopularniejsze typy treści, z którymi się zetknąłem, to application / xml i application / json.

Application / xml:

  • data-size: XML bardzo zwięzły, ale zazwyczaj nie stanowi problemu przy użyciu kompresji i myśleniu, że sprawa dostępu do zapisu (np. poprzez POST lub PUT) jest znacznie rzadsza niż dostęp do odczytu (w wielu przypadkach stanowi
  • istnienie znaków innych niż ascii: możesz użyć utf-8 jako kodowania w XML
  • istnienie danych binarnych: trzeba by użyć base64 kodowanie
  • dane nazwy pliku: możesz zamknąć to wewnętrzne pole w XML

Application / json

  • Rozmiar danych: bardziej zwarty mniej niż XML, nadal tekst, ale można skompresować
  • znaki inne niż ascii: json to utf-8
  • dane binarne: base64 (Zobacz także json-binary-question )
  • dane nazwy pliku: enkapsuluj jako własną sekcję pola w json

Dane binarne jako zasoby własne

Chciałbym reprezentować dane binarne jako własne zasoby/zasoby. Dodaje kolejne połączenie, ale lepiej odsprzęga rzeczy. Przykładowe obrazy:

POST /images
Content-type: multipart/mixed; boundary="xxxx" 
... multipart data

201 Created
Location: http://imageserver.org/../foo.jpg  

W późniejszych zasobach można po prostu wstawić link do zasobu binarnego:

<main-resource&gt
 ...
 <link href="http://imageserver.org/../foo.jpg"/>
</main-resource>
 82
Author: manuel aldana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:47

Zgadzam się z tym, co powiedział Manuel. W rzeczywistości jego komentarze odnoszą się do tego adresu url...

Http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4

... który stwierdza:

Typ zawartości "application / x-www-form-urlencoded" is nieefektywne wysyłanie dużych ilość danych binarnych lub tekstu zawierające znaki inne niż ASCII. Na content type " multipart / form-data" powinny być wykorzystywane do składania formularzy które zawierają pliki, Dane inne niż ASCII, i dane binarne.

Jednak dla mnie sprowadza się to do wsparcia narzędzi / frameworków.

  • jakie narzędzia i frameworki oczekuj, że użytkownicy API będą budować ich aplikacje z?
  • czy mają frameworków lub komponentów, z których mogą korzystać które faworyzują jedną metodę ponad inne?

Jeśli masz jasne pojęcie o swoich użytkownikach i jak będą korzystać z twojego API, to pomoże Ci to podjąć decyzję. Jeśli utrudnisz przesyłanie plików użytkownikom API, odejdą, a Ty poświęcisz dużo czasu na ich wspieranie.

Wtórne do tego byłoby wsparcie narzędzia masz do pisania API i jak łatwo jest dla ciebie, aby pomieścić jeden mechanizm przesyłania na drugi.

 26
Author: Martin Peck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-03 14:53:57

Mała podpowiedź z mojej strony do przesyłania danych obrazu HTML5 canvas:

Pracuję nad projektem dla drukarni i miałem pewne problemy z przesyłaniem obrazów na serwer, które pochodzą z elementu HTML5 canvas. Walczyłem przez co najmniej godzinę i nie udało mi się poprawnie zapisać obrazu na moim serwerze.

Po ustawieniu contentType opcja mojego wywołania jQuery ajax do application/x-www-form-urlencoded wszystko poszło dobrze i zakodowane w base64 dane zostały poprawnie zinterpretowane i pomyślnie zapisany jako obraz.


Może to komuś pomoże!
 0
Author: Torsten Barthel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-22 10:10:02

Jeśli chcesz użyć Content-Type=x-www-urlencoded-form to nie używaj FormDataCollection jako parametru: In asp.net Core 2 + FormDataCollection nie ma domyślnych konstruktorów, które są wymagane przez Formatery. Zamiast tego użyj IFormCollection:

 public IActionResult Search([FromForm]IFormCollection type)
    {
        return Ok();
    }
 0
Author: jahansha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-02 18:52:24