W jaki sposób parametry są wysyłane w żądaniu HTTP POST?

1475

W żądaniu HTTP GET parametry są wysyłane jako ciąg zapytania :

http://example.com/page ? parametr = wartość, a także = inny

W żądaniu HTTP POST parametry nie są wysyłane wraz z identyfikatorem URI.

Gdzie są wartości? W nagłówku żądania? W treści wniosku? Jak to wygląda?

Camilo Martin
źródło

Odpowiedzi:

1252

Wartości są wysyłane w treści żądania w formacie określonym przez typ zawartości.

Zazwyczaj typem treści jest application/x-www-form-urlencoded, więc treść żądania używa tego samego formatu, co ciąg zapytania:

parameter=value&also=another

Gdy używasz przesyłania pliku w formularzu, multipart/form-datazamiast tego używasz kodowania, które ma inny format. Jest to bardziej skomplikowane, ale zwykle nie musisz dbać o to, jak to wygląda, więc nie pokażę przykładu, ale dobrze jest wiedzieć, że istnieje.

Guffa
źródło
25
Zapomniałem, że przesyłanie plików jest inne (+ 1 / zaakceptowane). Twoja odpowiedź jest wystarczająca, ale byłoby miło, gdyby zawierała więcej informacji multipart/form-data. Dla zainteresowanych, oto pytanie na ten temat .
Camilo Martin
73
UWAGA : treść jest oddzielona od nagłówka tylko jedną pustą linią .
Gab 是 好人
2
Wyjaśniłeś, co umieszczamy w HTTPBody, ale co umieszczamy / piszemy w HTTPHeader? Do czego to służy?
Honey
4
@Honey: Nagłówek HTTP dla posta wygląda jak jeden dla get, ale z czasownikiem POST zamiast GET i wartością typu treści (i opcjonalną wartością długości treści), ponieważ żądanie ma treść (treść). Każdy typ żądania ma nagłówek, niektóre typy również mają treść.
Guffa
4
@KennethWorden Nie, żadna z metod nie wyśle ​​poprawnie JSON. możesz jednak przesłać plik json w postaci zakodowanej za pomocą multipart/form-datalub, jeśli jesteś odpowiedzialny za budowę żądania, zmień typ zawartości na application/jsoni wklej bezpośrednio tekst json w treści http
Cholthi Paul Ttiopic
428

Treść jest umieszczana za nagłówkami HTTP. Format HTTP POST ma mieć nagłówki HTTP, po których następuje pusty wiersz, a następnie treść żądania. Zmienne POST są przechowywane w ciele jako pary klucz-wartość.

Możesz to zobaczyć w surowej treści postu HTTP, pokazanej poniżej:

POST /path/script.cgi HTTP/1.0
From: [email protected]
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

home=Cosby&favorite+flavor=flies

Możesz to zobaczyć za pomocą narzędzia takiego jak Fiddler , którego możesz użyć do oglądania surowego żądania HTTP i ładunków odpowiedzi przesyłanych przez sieć.

Joe Alfano
źródło
39
Tylko jeśli typ zawartości jest taki application/x-www-form-urlencoded, co nie zawsze ma miejsce.
Guffa
@ Camilo Martin .... [+1] za świetne pytanie i @ Joe Alfano .... [+1] za świetną odpowiedź ....... mam teraz jasny pomysł na żądanie POST .... ale jeśli obraz zawiera klucz, wartość para informacji o danych ... Jak wygląda struktura testu POST?
Devrath,
9
@Joe, dlaczego miałbyś Fromtam nagłówek?
Pacerier,
@Joe, uwielbiam losowe włączanie Fromnagłówka. IMO jest tam z kodem statusu 418 HTTP.
Tom Howard
jak dodać uwierzytelnianie użytkownika i hasła?
m4l490n
376

Krótka odpowiedź: w żądaniach POST wartości są wysyłane w „treści” żądania. Formularze internetowe są najprawdopodobniej wysyłane z mediami typu application/x-www-form-urlencodedlub multipart/form-data. Języków programowania lub ram, które zostały zaprojektowane do obsługi wniosków internetowych zwykle zrobić „słuszne ™” z takimi wnioskami i zapewniają łatwy dostęp do łatwo dekodowane wartości (jak $_REQUESTalbo $_POSTw PHP, lub cgi.FieldStorage(), flask.request.formw Pythonie).


Teraz trochę wypisujemy, co może pomóc zrozumieć różnicę;)

Różnica pomiędzy GETi POSTwnioski są w znacznej mierze semantyczny. Są również „używane” w różny sposób, co wyjaśnia różnicę w przekazywaniu wartości.

GET ( odpowiednia sekcja RFC )

Podczas wykonywania GETżądania użytkownik prosi serwer o jeden lub zestaw encji. Aby umożliwić klientowi odfiltrowanie wyniku, może użyć tak zwanego „ciągu zapytania” adresu URL. Ciąg zapytania jest częścią po ?. Jest to część składni URI .

Tak więc, z punktu widzenia kodu aplikacji (części, która otrzymuje żądanie), konieczne będzie sprawdzenie części zapytania URI, aby uzyskać dostęp do tych wartości.

Pamiętaj, że klucze i wartości są częścią identyfikatora URI. Przeglądarki mogą nakładać ograniczenie długości identyfikatora URI. Standard HTTP stwierdza, że ​​nie ma limitu. Ale w chwili pisania tego tekstu, większość przeglądarek nie ograniczają URI (nie mam konkretnych wartości). GETżądania nigdy nie powinny być wykorzystywane do przesyłania nowych informacji do serwera. Zwłaszcza nie większe dokumenty. Właśnie tam powinieneś użyć POSTlub PUT.

POST ( odpowiednia sekcja RFC )

Podczas wykonywania POSTżądania klient faktycznie przesyła nowy dokument do zdalnego hosta. Zatem ciąg zapytania nie ma (semantycznego) sensu. Dlatego nie masz dostępu do nich w kodzie aplikacji.

POSTjest nieco bardziej skomplikowany (i znacznie bardziej elastyczny):

Po otrzymaniu żądania POST należy zawsze oczekiwać „ładunku” lub, w kategoriach HTTP: treści wiadomości . Treść wiadomości sama w sobie jest dość bezużyteczna, ponieważ nie ma standardowego formatu (o ile wiem. Może format aplikacji / octet-stream?). Format treści jest definiowany przez Content-Typenagłówek. W przypadku użycia FORMelementu HTML z method="POST"jest to zwykle application/x-www-form-urlencoded. Innym bardzo popularnym typem jest wieloczęściowy / formularz-dane, jeśli używasz przesyłania plików. Ale może to być wszystko , od text/plain, ponad, application/jsona nawet zwyczaj application/octet-stream.

W każdym przypadku, jeśli zostanie POSTwysłane żądanie, Content-Typektórego aplikacja nie może obsłużyć, powinno zwrócić 415kod stanu .

Większość języków programowania (i / lub Web-ram) oferują sposób na DE / zakodować treść wiadomości do / z najczęstszych typów (jak application/x-www-form-urlencoded, multipart/form-datalub application/json). To takie proste. Typy niestandardowe wymagają potencjalnie nieco więcej pracy.

Korzystając ze standardowego dokumentu zakodowanego w formularzu HTML jako przykładu, aplikacja powinna wykonać następujące kroki:

  1. Przeczytaj Content-Typepole
  2. Jeśli wartość nie jest jednym z obsługiwanych typów nośników, zwróć odpowiedź z 415kodem stanu
  3. w przeciwnym razie zdekoduj wartości z treści wiadomości.

Znowu języki takie jak PHP lub frameworki dla innych popularnych języków prawdopodobnie to zapewnią. Wyjątkiem jest 415błąd. Żadna struktura nie jest w stanie przewidzieć, jakie typy treści wybiera aplikacja do obsługi i / lub nie. To zależy od Ciebie.

PUT ( odpowiednia sekcja RFC )

PUTWniosek jest dość dużo traktowane w dokładnie taki sam sposób, jak POSTżądanie. Duża różnica polega na tym, że POSTżądanie ma pozwolić serwerowi zdecydować, w jaki sposób (a jeśli w ogóle) stworzyć nowy zasób. Historycznie (z przestarzałego RFC2616 było tworzenie nowego zasobu jako „podrzędny” (potomek) identyfikatora URI, do którego wysłano żądanie).

Natomiast PUTżądanie ma „zdeponować” zasób dokładnie pod tym identyfikatorem URI i dokładnie z tą zawartością. Nie więcej nie mniej. Chodzi o to, że klient jest odpowiedzialny za wytworzenie całego zasobu przed jego „umieszczeniem”. Serwer powinien zaakceptować to, co jest na danym adresie URL.

W rezultacie POSTżądanie zwykle nie jest używane do zastąpienia istniejącego zasobu. PUTŻądanie może zrobić zarówno tworzyć i wymieniać.

Dygresja

Istnieją również „ parametry ścieżki ”, których można użyć do przesłania dodatkowych danych do pilota, ale są one tak rzadkie, że nie będę tu wchodził w szczegóły. Ale, dla odniesienia, oto fragment RFC:

Oprócz segmentów kropek w ścieżkach hierarchicznych, segment ścieżki jest uważany za nieprzezroczysty przez ogólną składnię. Aplikacje wytwarzające identyfikatory URI często używają znaków zastrzeżonych dozwolonych w segmencie, aby rozgraniczać podskładniki specyficzne dla schematu lub specyficzne dla procedury obsługi odniesienia. Na przykład znaki zastrzeżone średnika („;”) i równe („=”) są często używane do rozgraniczenia parametrów i wartości parametrów mających zastosowanie do tego segmentu. Znak podobny do przecinka („,”) jest często używany do podobnych celów. Na przykład jeden producent URI może użyć segmentu takiego jak „nazwa; v = 1.1”, aby wskazać odniesienie do wersji 1.1 „nazwa”, podczas gdy inny może użyć segmentu takiego jak „nazwa, 1.1”, aby wskazać to samo. Typy parametrów mogą być definiowane przez semantykę specyficzną dla schematu,

ekshuma
źródło
1
Mógłbym rzeczywiście mieć niewielką styczną. Dodałem „tl; dr” na górze odpowiedzi, co powinno uczynić ją bardziej zrozumiałą.
ekshuma
Właśnie go teraz edytowałem, aby odwoływał się do RFC7231 zamiast RFC2616 (który był już przestarzały). Główną różnicą dla tej odpowiedzi, oprócz zaktualizowanych linków, jest sekcja „PUT”.
ekshuma
Myślałem, że PUT jest obsługiwany inaczej niż POST, ponieważ ma być idempotentny? stackoverflow.com/questions/611906/…
rogerdpack
1
@rogerdpack Nie pomylisz się. Jeśli przeczytasz drugi akapit w tej PUTsekcji, zobaczysz, że jest idempotentny. POSTprzeciwnie - z definicji nie może być. POSTzawsze utworzy nowy zasób. PUTbędzie, jeśli istnieje identyczny zasób, zastąpi go. Więc jeśli zadzwonisz POST10 razy, stworzysz 10 zasobów. Jeśli zadzwonisz PUT10 razy, utworzy (może) tylko jeden. Czy to jest odpowiedź na Twoje pytanie?
ekshuma
59

Nie możesz wpisać go bezpośrednio na pasku adresu URL przeglądarki.

Możesz zobaczyć, jak dane POST są wysyłane przez Internet, na przykład za pomocą nagłówków Live HTTP . Wynik będzie taki

http://127.0.0.1/pass.php
POST /pass.php HTTP/1.1

Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://127.0.0.1/pass.php
Cookie: passx=87e8af376bc9d9bfec2c7c0193e6af70; PHPSESSID=l9hk7mfh0ppqecg8gialak6gt5
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
username=zurfyx&pass=password

Gdzie to mówi

Content-Length: 30
    username=zurfyx&pass=password

będą wartościami postu.

zurfyx
źródło
2
Wyjaśnienie: Content-Lengthma 29tu być ? To jest rzeczywista długość łańcucha username=zurfyx&pass=password.
Hippo
@Hippo był postacią z nowej linii?
vikingsteve
@vikingsteve Rozumiem, co masz na myśli. Sądzę więc, że treść zawsze ma na końcu nowy wiersz.
Hippo
2
Nagłówek jest oddzielony od treści dodatkową linią
Mára Toner
24

Domyślny typ nośnika w żądaniu POST to application/x-www-form-urlencoded. Jest to format kodowania par klucz-wartość. Klucze mogą być duplikowane. Każda para klucz-wartość jest oddzielona &znakiem, a każdy klucz jest oddzielony od swojej wartości =znakiem.

Na przykład:

Name: John Smith
Grade: 19

Jest zakodowany jako:

Name=John+Smith&Grade=19

Jest to umieszczane w treści żądania za nagłówkami HTTP.

Nejat
źródło
1
Wyjaśniłeś, co umieszczamy w HTTPBody, ale co umieszczamy / piszemy w HTTPHeader?
Honey
Wspomniałeś, że klucz może być duplikatem, a jaki jest wynik takiego duplikatu? Czy ostatnia automatycznie nadpisze poprzednie wartości? Dzięki.
Jinghui Niu
@JinghuiNiu, jeśli klucz jest zduplikowany, należy go przeanalizować jako tablicę. Jest bardzo późno, ale może pomóc komuś innemu.
Hanash Yaslem,
18

Wartości formularzy w POST HTTP są wysyłane w treści żądania, w tym samym formacie co kwerenda.

Aby uzyskać więcej informacji, zobacz specyfikację .

SLaks
źródło
5
„Ten sam format” jest nieco niejednoznaczny. Czy zaczynają się ?na przykład?
Camilo Martin
7
@PeterWooster Tak, ale nie podaje przykładu. Pod tym względem jest jak odpowiedź, która mówi „patrz, odpowiedź na twoje pytanie znajduje się w blogu aplikacji (link) ”.
Camilo Martin
36
@PeterWooster To nie jest potrzebne, ale jest bardzo dobre, gdy coś zapomnisz, google, przejdź do pierwszego linku, który jest SO, i jest jasny, zwięzły przykład, który mówi ci, czego potrzebujesz, zamiast wysyłać cię do gryzienia zbyt szczegółowe specyfikacje, które nawet jeśli są wyczerpujące, mogą nie nadawać się do odświeżania. Pomyśl o tym: większość kontroli jakości na tej stronie może sprowadzać się do „przejdź do specyfikacji / manual / API / etc (link) ”. Czy byłoby to przydatne? Nie więcej niż Google.
Camilo Martin
2
Tylko jeśli typ zawartości jest taki application/x-www-form-urlencoded, co nie zawsze ma miejsce.
Guffa
3
Format ciągu zapytania GET różni się od formatu application / x-www-form-urlencoded. Na przykład białe znaki są kodowane inaczej (% 20 vs +). Odpowiedź jest myląca w tym względzie.
UnclickableCharacter
18

Niektóre usługi internetowe wymagają oddzielnego umieszczania danych żądania i metadanych . Na przykład funkcja zdalna może oczekiwać, że podpisany ciąg metadanych jest zawarty w identyfikatorze URI, podczas gdy dane są publikowane w treści HTTP.

Żądanie POST może semantycznie wyglądać następująco:

POST /?AuthId=YOURKEY&Action=WebServiceAction&Signature=rcLXfkPldrYm04 HTTP/1.1
Content-Type: text/tab-separated-values; charset=iso-8859-1
Content-Length: []
Host: webservices.domain.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)

name    id
John    G12N
Sarah   J87M
Bob     N33Y

Podejście to logicznie łączy QueryString i Body-Post za pomocą jednego, Content-Typektóry jest „instrukcją parsowania” dla serwera WWW.

Uwaga: HTTP / 1.1 jest owinięty z #32(spacja) na lewo i #10(Line Feed) po prawej stronie.

Interfejs nieznany
źródło
Różnica między /user/johni /?user=johnjest jedynie semantyczna (HTTP tak naprawdę nie traktuje specjalnych ciągów zapytań), więc uważam to za uzasadnione. Ale co rozumiesz przez „owinięty spacją po lewej stronie”? Nie ma spacji przed metodą HTTP. Masz na myśli pustą linię na treść postu?
Camilo Martin
Jest to przestrzeń (ASCII 32) pomiędzy ...Ym04i HTTP/1.1w powyższym kodzie. Zatem QueryString po prostu znajduje się między czasownikiem a wersją protokołu.
Interfejs nieznany
1
Twoja notatka sprawia, że ​​brzmi to jak coś nieoczekiwanego i specyficznego dla wersji. Szczerze mówiąc wydaje się oczywiste, że jest tam miejsce. Odsyłacz do wiersza dotyczy również innych wierszy, takich jak wszystkie rzeczy uniksowe.
Camilo Martin
1
Właśnie podkreśliłem to, czego nie mogłem zaznaczyć w kodzie. Może się to wydawać oczywiste, ale czasem tak nie jest.
Interfejs nieznany
Prawdą jest, że możemy przekazać parametry zapytania jako część adresu URL, oddzielając identyfikator URI i parametry w sposób ?podobny do GETżądania.
asgs
8

Po pierwsze, rozróżnijmy między GETiPOST

Pobierz: Jest to domyślne HTTPżądanie wysyłane do serwera, które służy do pobierania danych z serwera, a ciąg zapytania, który pojawia się po ?w, URIsłuży do pobierania unikalnego zasobu.

to jest format

GET /someweb.asp?data=value HTTP/1.0

tutaj data=valueprzekazano wartość ciągu zapytania.

POST: Służy do bezpiecznego przesyłania danych do serwera, więc wszystko, co jest potrzebne, jest to format POSTżądania

POST /somweb.aspHTTP/1.0
Host: localhost
Content-Type: application/x-www-form-urlencoded //you can put any format here
Content-Length: 11 //it depends
Name= somename

Dlaczego POST zamiast GET?

Ponieważ GETwartość wysyłana do serwerów jest zwykle dołączana do podstawowego adresu URL w ciągu zapytania, teraz występują 2 tego konsekwencje

  • Te GETwnioski są zapisywane w historii przeglądarki z parametrami. Twoje hasła pozostają więc niezaszyfrowane w historii przeglądarki. To był prawdziwy problem dla Facebooka w tamtych czasach.
  • Zwykle serwery mają limit czasu trwania URI. Jeśli wysłano zbyt wiele parametrów, możesz otrzymać414 Error - URI too long

W przypadku żądania wysłania dane z pól są dodawane do treści. Długość parametrów żądania jest obliczana i dodawana do nagłówka dla długości treści, a żadne ważne dane nie są dołączane bezpośrednio do adresu URL.

Możesz użyć sekcji sieci Narzędzi Google dla programistów, aby wyświetlić podstawowe informacje na temat wysyłania żądań do serwerów.

i zawsze można dodać więcej wartości w Request HeadersLike Cache-Control, Origin, Accept.

Zeeshan Adil
źródło
4
Założenia dotyczące bezpieczeństwa są prawdziwe tylko w kontekście HTTPSpołączenia, a nie HTTP. HTTPSszyfruje zarówno URL(w tym parametry zapytania), jak i Request Body, gdy HTTPszyfruje / nie chroni. Opisany problem wynika z faktu, że wiele przeglądarek przechowuje URIs(w tym URLs) w swoich historycznych bazach danych (zwykle niezaszyfrowanych). Dlatego używaj tylko Request Body+ HTTPSdo czegokolwiek wrażliwego.
Petru Zaharia,
@PetruZaharia Zgadzam się z twoim wyjaśnieniem. Możesz również zasugerować to jako edycję, a ja chętnie to zaakceptuję! :)
Zeeshan Adil