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.
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
[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.
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
.
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>
...
<link href="http://imageserver.org/../foo.jpg"/>
</main-resource>
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.
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!
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();
}
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