Come vengono inviati i parametri in una richiesta POST HTTP?


1476

In una richiesta HTTP GET , i parametri vengono inviati come stringa di query :

http://example.com/page ? parametro = valore e anche = altro

In una richiesta POST HTTP , i parametri non vengono inviati insieme all'URI.

Dove sono i valori? Nell'intestazione della richiesta? Nel corpo della richiesta? Che cosa sembra?

Risposte:


1254

I valori vengono inviati nel corpo della richiesta, nel formato specificato dal tipo di contenuto.

Di solito è il tipo di contenuto application/x-www-form-urlencoded, quindi il corpo della richiesta utilizza lo stesso formato della stringa di query:

parameter=value&also=another

Quando si utilizza un caricamento di file nel modulo, si utilizza multipart/form-datainvece la codifica, che ha un formato diverso. È più complicato, ma di solito non devi preoccuparti di come appare, quindi non mostrerò un esempio, ma può essere utile sapere che esiste.


25
Mi ero dimenticato che i caricamenti di file erano diversi (+ 1 / accettato). La tua risposta è sufficiente, mentre sarebbe molto più bello se avesse più informazioni su multipart/form-data. Per coloro che sono interessati, ecco una domanda al riguardo .
Camilo Martin,

73
NOTA : il corpo è separato dall'intestazione da una sola riga vuota .
Gab 是 好人

2
Hai spiegato cosa inseriamo in HTTPBody, ma cosa inseriamo / scriviamo in HTTPHeader? A quale scopo serve?
Miele,

4
@Honey: L'intestazione HTTP per un post sembra simile a uno per un get, ma con il verbo POST invece di GET e un valore del tipo di contenuto (e un valore di lunghezza del contenuto facoltativo) poiché la richiesta ha contenuto (corpo). Ogni tipo di richiesta ha un'intestazione, alcuni tipi hanno anche un corpo.
Guffa,

4
@KennethWorden No, nessuno dei metodi invierà correttamente JSON. puoi comunque caricare un file json in una forma codificata con multipart/form-datao se sei responsabile della costruzione della richiesta, cambiare il tipo di contenuto in application/jsone incollare direttamente il testo json nel corpo http
Cholthi Paul Ttiopic

428

Il contenuto viene inserito dopo le intestazioni HTTP. Il formato di un POST HTTP è di avere le intestazioni HTTP, seguite da una riga vuota, seguita dal corpo della richiesta. Le variabili POST sono memorizzate come coppie chiave-valore nel corpo.

Puoi vederlo nel contenuto non elaborato di un post HTTP, mostrato di seguito:

POST /path/script.cgi HTTP/1.0
From: frog@jmarshall.com
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

home=Cosby&favorite+flavor=flies

Puoi vederlo utilizzando uno strumento come Fiddler , che puoi utilizzare per guardare la richiesta HTTP non elaborata e i payload di risposta inviati attraverso il cavo.


39
Solo se il tipo di contenuto è application/x-www-form-urlencoded, che non è sempre il caso.
Guffa,

@ Camilo Martin .... [+1] per una grande domanda e @ Joe Alfano .... [+1] per una grande risposta ....... ora ho un'idea chiara della richiesta POST .... ma se un'immagine viene fornita con una chiave, una coppia di valori di informazioni di dati ..... Come appare la struttura di POST?
Devrath,

9
@Joe, ora perché dovresti avere Fromun'intestazione lì?
Pacerier,

@Joe, adoro l'inclusione casuale Fromdell'intestazione. IMO è lassù con il codice di stato HTTP 418.
Tom Howard,

come si aggiunge un'autenticazione utente e password?
m4l490n

376

Risposta breve: nelle richieste POST, i valori vengono inviati nel "corpo" della richiesta. Con i moduli Web sono molto probabilmente inviati con un tipo di supporto application/x-www-form-urlencodedo multipart/form-data. I linguaggi di programmazione o i framework che sono stati progettati per gestire le richieste Web di solito fanno "The Right Thing ™" con tali richieste e offrono un facile accesso ai valori prontamente decodificati (come $_REQUESTo $_POSTin PHP, o cgi.FieldStorage(), flask.request.formin Python).


Ora divagiamo un po ', il che può aiutare a capire la differenza;)

La differenza tra GETe le POSTrichieste sono in gran parte semantiche. Sono anche "usati" in modo diverso, il che spiega la differenza nel modo in cui i valori vengono passati.

OTTIENI ( sezione RFC pertinente )

Quando si esegue una GETrichiesta, si richiede al server una o una serie di entità. Per consentire al client di filtrare il risultato, può utilizzare la cosiddetta "stringa di query" dell'URL. La stringa di query è la parte dopo il ?. Questo fa parte della sintassi dell'URI .

Pertanto, dal punto di vista del codice dell'applicazione (la parte che riceve la richiesta), sarà necessario ispezionare la parte della query URI per accedere a questi valori.

Si noti che le chiavi e i valori fanno parte dell'URI. I browser possono imporre un limite alla lunghezza dell'URI. Lo standard HTTP afferma che non esiste alcun limite. Ma al momento in cui scriviamo, la maggior parte dei browser non limitano gli URI (non ho valori specifici). GETle richieste non devono mai essere utilizzate per inviare nuove informazioni al server. Soprattutto documenti non più grandi. Ecco dove dovresti usare POSTo PUT.

POST ( sezione RFC pertinente )

Quando esegue una POSTrichiesta, il client sta effettivamente inviando un nuovo documento all'host remoto. Pertanto, una stringa di query non ha senso (semanticamente). Ecco perché non puoi accedervi nel codice dell'applicazione.

POSTè un po 'più complesso (e molto più flessibile):

Quando ricevi una richiesta POST, dovresti sempre aspettarti un "payload" o, in termini HTTP: un corpo di messaggio . Il corpo del messaggio in sé è piuttosto inutile, in quanto non esiste un formato standard (per quanto ne so. Forse application / octet-stream?). Il formato del corpo è definito dall'intestazione Content-Type. Quando si utilizza un FORMelemento HTML con method="POST", questo è di solito application/x-www-form-urlencoded. Un altro tipo molto comune è multipart / form-data se si utilizzano i caricamenti di file. Ma potrebbe essere qualsiasi cosa , che va da text/plain, sopra application/jsono addirittura un'usanza application/octet-stream.

In ogni caso, se POSTviene fatta una richiesta con una Content-Typeche non può essere gestita dall'applicazione, dovrebbe restituire un 415codice di stato .

La maggior parte dei linguaggi di programmazione (e / o web framework) offre un modo per de / codificare il corpo del messaggio da / verso i tipi più comuni (come application/x-www-form-urlencoded, multipart/form-datao application/json). Quindi è facile. I tipi personalizzati richiedono potenzialmente un po 'più di lavoro.

Utilizzando come esempio un documento codificato in un modulo HTML standard, l'applicazione dovrebbe eseguire i seguenti passaggi:

  1. Leggi il Content-Typecampo
  2. Se il valore non è uno dei tipi di supporto supportati, restituire una risposta con un 415codice di stato
  3. in caso contrario, decodificare i valori dal corpo del messaggio.

Ancora una volta, lingue come PHP o web framework per altre lingue popolari probabilmente gestiranno questo per te. L'eccezione a questo è l' 415errore. Nessun framework può prevedere quali tipi di contenuto la tua applicazione sceglie di supportare e / o non supportare. Questo lo devi decidere tu.

PUT ( pertinente sezione RFC )

Una PUTrichiesta viene gestita praticamente nello stesso modo di una POSTrichiesta. La grande differenza è che una POSTrichiesta dovrebbe consentire al server di decidere come (e se non del tutto) creare una nuova risorsa. Storicamente (dall'ormai obsoleto RFC2616 era creare una nuova risorsa come "subordinata" (figlio) dell'URI a cui era stata inviata la richiesta).

Una PUTrichiesta al contrario dovrebbe "depositare" una risorsa esattamente in quell'URI e con esattamente quel contenuto. Ne più ne meno. L'idea è che il cliente abbia la responsabilità di creare la risorsa completa prima di "inserirla". Il server dovrebbe accettarlo così com'è nell'URL indicato.

Di conseguenza, una POSTrichiesta non viene in genere utilizzata per sostituire una risorsa esistente. Una PUTrichiesta può sia creare che sostituire.

Nota a margine

Esistono anche " parametri di percorso " che possono essere utilizzati per inviare dati aggiuntivi al telecomando, ma sono così insoliti che non entrerò in troppi dettagli qui. Ma, per riferimento, ecco un estratto dall'RFC:

A parte i segmenti di punti nei percorsi gerarchici, un segmento di percorso è considerato opaco dalla sintassi generica. Le applicazioni che producono URI utilizzano spesso i caratteri riservati consentiti in un segmento per delimitare i sottocomponenti specifici dello schema o del gestore della dereference. Ad esempio, i punti riservati punto e virgola (";") e uguale ("=") vengono spesso utilizzati per delimitare i parametri e i valori dei parametri applicabili a quel segmento. Il carattere riservato virgola (",") viene spesso utilizzato per scopi simili. Ad esempio, un produttore di URI potrebbe utilizzare un segmento come "nome; v = 1.1" per indicare un riferimento alla versione 1.1 di "nome", mentre un altro potrebbe utilizzare un segmento come "nome, 1.1" per indicare lo stesso. I tipi di parametro possono essere definiti dalla semantica specifica dello schema,


1
Potrei aver preso una leggera tangente. Ho aggiunto un "tl; dr" all'inizio della risposta che dovrebbe renderlo più chiaro.
exhuma,

L'ho modificato anche solo ora per fare riferimento a RFC7231 anziché a RFC2616 (che è stato obsoleto per un po '). La differenza principale per questa risposta a parte i collegamenti aggiornati, è nella sezione "PUT".
exhuma,

Pensavo che il PUT fosse gestito diversamente dal POST poiché doveva essere idempotente? stackoverflow.com/questions/611906/...
rogerdpack

1
@rogerdpack Non hai torto. Se leggi il secondo paragrafo nella PUTsezione, vedrai che è idempotente. POSTal contrario, per definizione, non può essere. POSTcreerà sempre una nuova risorsa. PUTsostituirà se esiste una risorsa identica. Quindi, se chiami POST10 volte, creerai 10 risorse. Se chiami PUT10 volte, ne creerà (forse) solo una. Questo risponde alla tua domanda?
exhuma,

60

Non puoi digitarlo direttamente sulla barra degli URL del browser.

Ad esempio, puoi vedere come vengono inviati i dati POST su Internet con le intestazioni HTTP in tempo reale . Il risultato sarà qualcosa del genere

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

Dove dice

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

saranno i valori dei post.


2
Chiarimento: Content-Lengthdovrebbe essere 29qui? Questa è la lunghezza effettiva della stringa username=zurfyx&pass=password.
Ippopotamo,

@Hippo era un personaggio newline pensato per essere lì?
vikingsteve,

@vikingsteve Capisco cosa intendi. Quindi suppongo che il Contenuto abbia sempre una nuova riga alla fine, quindi.
Ippopotamo,

2
L'intestazione è separata dal corpo con una nuova riga aggiuntiva
Mára Toner,

24

Il tipo di supporto predefinito in una richiesta POST è application/x-www-form-urlencoded. Questo è un formato per la codifica di coppie chiave-valore. Le chiavi possono essere duplicate. Ogni coppia chiave-valore è separata da un &carattere e ogni chiave è separata dal suo valore da un =carattere.

Per esempio:

Name: John Smith
Grade: 19

È codificato come:

Name=John+Smith&Grade=19

Questo viene inserito nel corpo della richiesta dopo le intestazioni HTTP.


1
Hai spiegato cosa inseriamo in HTTPBody, ma cosa inseriamo / scriviamo in HTTPHeader?
Miele,

Hai detto che la chiave può essere duplicata, allora qual è il risultato di un tale duplicato? L'ultimo sovrascriverà automaticamente i valori precedenti? Grazie.
Jinghui Niu,

@JinghuiNiu se la chiave è duplicata, deve essere analizzata come matrice. È molto tardi, ma potrebbe aiutare qualcun altro.
Hanash Yaslem,

18

I valori dei moduli nei POST HTTP vengono inviati nel corpo della richiesta, nello stesso formato della stringa di query.

Per ulteriori informazioni, consultare le specifiche .


5
"Lo stesso formato" è un po 'ambiguo. Cominciano con un ?esempio?
Camilo Martin,

7
@PeterWooster Sì, ma non fornisce un esempio. A tale proposito, è come una risposta che dice "guarda, c'è una risposta per la tua domanda nel blog dell'applicazione (link) ".
Camilo Martin,

36
@PeterWooster Non è necessario, ma è molto buono quando dimentichi qualcosa, cercalo su Google, vai al primo link che è SO, e c'è un esempio chiaro e conciso che ti dice cosa ti serve invece di mandarti a masticare sul specifiche eccessivamente dettagliate che, anche se complete, potrebbero non essere adatte ai rinfrescanti. Pensaci: la maggior parte dei QA su questo sito potrebbe essere ridotta a "vai a leggere le specifiche / manuale / API / etc (link) ". Sarebbe utile? Non più di Google.
Camilo Martin,

2
Solo se il tipo di contenuto è application/x-www-form-urlencoded, che non è sempre il caso.
Guffa,

3
Il formato della stringa di query GET è diverso da quello dell'applicazione / x-www-form-urlencoded. Ad esempio, gli spazi bianchi sono codificati in modo diverso (% 20 vs +). La risposta è fuorviante al riguardo.
UnclickableCharacter il

18

Alcuni dei servizi web richiedono di inserire i dati e i metadati della richiesta separatamente. Ad esempio, una funzione remota può prevedere che la stringa di metadati firmata sia inclusa in un URI, mentre i dati sono pubblicati in un corpo HTTP.

La richiesta POST può apparire semanticamente così:

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

Questo approccio combina logicamente QueryString e Body-Post usando un singolo Content-Typeche è una "istruzione di analisi" per un web server.

Nota: HTTP / 1.1 è racchiuso con #32(spazio) a sinistra e con #10(Avanzamento riga) a destra.


La differenza tra /user/johne /?user=johnè semplicemente semantica (HTTP non offre un trattamento speciale per le stringhe di query), quindi prendo questo come ragionevolmente previsto. Ma cosa intendi con "avvolto dallo spazio a sinistra"? Non ci sono spazi prima del metodo HTTP. Intendi la riga vuota per il corpo della posta?
Camilo Martin,

C'è uno spazio (ASCII # 32) tra ...Ym04e HTTP/1.1nel codice sopra. Quindi una QueryString risiede semplicemente tra il verbo e la versione del protocollo.
Interfaccia sconosciuta

1
La tua nota fa sembrare che sia qualcosa di inaspettato e specifico della versione. Francamente sembra ovvio che ci sia uno spazio lì. E il feed di riga si applica anche alle altre righe, come tutte le cose unix.
Camilo Martin,

1
Ho appena sottolineato ciò che non potevo segnare nel codice. Può sembrare ovvio ma a volte no.
Interfaccia sconosciuta il

È vero che potremmo passare i parametri della query come parte dell'URL separando l'URI e i parametri con un ?simile a quello che facciamo con le GETrichieste.
as

8

Prima di tutto, differenziamo tra GETePOST

Ottieni: è la HTTPrichiesta predefinita che viene effettuata al server e viene utilizzata per recuperare i dati dal server e la stringa di query che viene dopo ?in URIviene utilizzata per recuperare una risorsa univoca.

questo è il formato

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

ecco data=valueil valore della stringa di query passato.

POST: viene utilizzato per inviare i dati al server in modo sicuro, quindi tutto ciò che è necessario, questo è il formato di una POSTrichiesta

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

Perché POST over GET?

Nel GETvalore inviato ai server vengono generalmente aggiunti all'URL di base nella stringa di query, ora ci sono 2 conseguenze di questo

  • Le GETrichieste vengono salvate nella cronologia del browser con i parametri. Quindi le tue password rimangono non crittografate nella cronologia del browser. Ai giorni nostri questo era un vero problema per Facebook.
  • Di solito i server hanno un limite su quanto a URIpuò essere. Se hai inviato troppi parametri potresti ricevere414 Error - URI too long

In caso di richiesta post i tuoi dati dai campi vengono invece aggiunti al corpo. La lunghezza dei parametri della richiesta viene calcolata e aggiunta all'intestazione per la lunghezza del contenuto e nessun dato importante viene aggiunto direttamente all'URL.

Puoi utilizzare la sezione di rete degli Strumenti per gli sviluppatori di Google per visualizzare le informazioni di base su come vengono inviate le richieste ai server.

e si può sempre aggiungere più valori nel vostro Request Headerscome Cache-Control, Origin, Accept.


4
Le ipotesi sulla sicurezza sono vere solo nel contesto di una HTTPSconnessione, non HTTP. HTTPScrittografa sia URL(inclusi parametri di query) sia Request Body, quando non HTTPcrittografa / protegge nessuno dei due. Il problema descritto deriva dal fatto che molti browser memorizzano URIs(incluso URLs) nei loro database di cronologia (di solito non crittografati). Quindi, usa solo il Request Body+ HTTPSper qualcosa di sensibile.
Petru Zaharia,

@PetruZaharia Sono d'accordo con la tua spiegazione. Puoi anche suggerire questo come modifica e sarò felice di accettarlo! :)
Zeeshan Adil,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.