Risposte:
Quando si effettua una richiesta POST, è necessario codificare i dati che formano il corpo della richiesta in qualche modo.
I moduli HTML forniscono tre metodi di codifica.
application/x-www-form-urlencoded
(il predefinito)multipart/form-data
text/plain
Si stava lavorando per aggiungere application/json
, ma questo è stato abbandonato.
(Altre codifiche sono possibili con richieste HTTP generate utilizzando mezzi diversi dall'invio di un modulo HTML. JSON è un formato comune da utilizzare con i servizi Web e alcuni usano ancora SOAP.)
Le specifiche dei formati non contano per la maggior parte degli sviluppatori. I punti importanti sono:
text/plain
.Quando si scrive un codice lato client:
multipart/form-data
quando il modulo include <input type="file">
elementimultipart/form-data
o application/x-www-form-urlencoded
ma application/x-www-form-urlencoded
sarai più efficienteQuando si scrive un codice lato server:
La maggior parte (come quella di Perl CGI->param
o quella esposta dal $_POST
superglobal di PHP ) si prenderà cura delle differenze per te. Non preoccuparti di provare a analizzare l'input non elaborato ricevuto dal server.
A volte troverai una libreria che non è in grado di gestire entrambi i formati. La libreria più popolare di Node.js per la gestione dei dati dei moduli è body-parser che non è in grado di gestire richieste multipart (ma ha una documentazione che consiglia alcune alternative che possono).
Se stai scrivendo (o eseguendo il debug) di una libreria per l'analisi o la generazione di dati non elaborati, devi iniziare a preoccuparti del formato. Potresti anche volerlo sapere per interesse.
application/x-www-form-urlencoded
è più o meno uguale a una stringa di query alla fine dell'URL.
multipart/form-data
è significativamente più complicato ma consente di includere interi file nei dati. Un esempio del risultato può essere trovato nella specifica HTML 4 .
text/plain
è introdotto da HTML 5 ed è utile solo per il debug - dalle specifiche : non sono interpretabili in modo affidabile dal computer - e direi che gli altri combinati con strumenti (come il Pannello di rete negli strumenti di sviluppo della maggior parte dei browser) sono migliori per quello).
quando dovremmo usarlo
La risposta di Quentin è corretta: utilizzare multipart/form-data
se il modulo contiene un caricamento di file e application/x-www-form-urlencoded
, in caso contrario, è l'impostazione predefinita se si omette enctype
.
Sto andando a:
Esistono tre possibilità per enctype
:
application/x-www-form-urlencoded
multipart/form-data
(le specifiche indicano RFC7578 )text/plain
. Questo "non è interpretabile in modo affidabile dal computer", quindi non dovrebbe mai essere usato in produzione e non esamineremo più in dettaglio.Una volta che vedi un esempio di ciascun metodo, diventa ovvio come funzionano e quando dovresti usarli.
Puoi produrre esempi usando:
nc -l
o un server ECHO: server di prova HTTP che accetta richieste GET / POSTSalvare il modulo in un .html
file minimo :
<!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ω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>
Impostiamo il valore di testo predefinito su aωb
, il che significa aωb
perché ω
è U+03C9
, che sono i byte 61 CF 89 62
in UTF-8.
Crea file da caricare:
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
Esegui il nostro piccolo server echo:
while true; do printf '' | nc -l 8000 localhost; done
Apri l'HTML sul tuo browser, seleziona i file e fai clic su Invia e controlla il terminale.
nc
stampa la richiesta ricevuta.
Testato su: Ubuntu 14.04.3, nc
BSD 1.105, Firefox 40.
Firefox inviato:
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--
Per il file binario e il campo di testo, i byte 61 CF 89 62
( aωb
in UTF-8) vengono inviati letteralmente. Puoi verificarlo con nc -l localhost 8000 | hd
, che dice che i byte:
61 CF 89 62
sono stati inviati ( 61
== 'a' e 62
== 'b').
Pertanto è chiaro che:
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
imposta il tipo di contenuto su multipart/form-data
e dice che i campi sono separati dalla boundary
stringa data .
Ma nota che:
boundary=---------------------------735323031399963166993862150
ha due paphes in meno --
rispetto alla barriera reale
-----------------------------735323031399963166993862150
Questo perché lo standard richiede che il limite inizi con due trattini --
. Gli altri trattini sembrano essere proprio come Firefox ha scelto di implementare il confine arbitrario. RFC 7578 menziona chiaramente che --
sono necessari quei due trattini principali :
4.1. Parametro "Boundary" di multipart / form-data
Come con altri tipi multipart, le parti sono delimitate da un delimitatore di limite, costruito usando CRLF, "-" e il valore del parametro "limite".
ogni campo ottiene alcuni sottotitoli prima dei suoi dati:, Content-Disposition: form-data;
il campo name
, il filename
, seguito dai dati.
Il server legge i dati fino alla stringa di limite successiva. Il browser deve scegliere un limite che non verrà visualizzato in nessuno dei campi, quindi è per questo che il limite può variare tra le richieste.
Poiché abbiamo il limite univoco, non è necessaria alcuna codifica dei dati: i dati binari vengono inviati così come sono.
TODO: qual è la dimensione del limite ottimale ( log(N)
scommetto) e il nome / tempo di esecuzione dell'algoritmo che lo trova? Chiesto a: /cs/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequences
Content-Type
viene determinato automaticamente dal browser.
Come viene determinato esattamente è stato chiesto a: Come viene determinato il tipo mime di un file caricato dal browser?
Ora modifica il enctype
in application/x-www-form-urlencoded
, ricarica il browser e reinvia.
Firefox inviato:
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
Chiaramente i dati del file non sono stati inviati, solo i nomi di base. Quindi questo non può essere usato per i file.
Per quanto riguarda il campo di testo, vediamo che al solito i caratteri stampabili come a
e b
sono stati inviati in un byte, mentre quelli non stampabili come 0xCF
e 0x89
presero 3 byte ciascuno: %CF%89
!
I caricamenti di file contengono spesso molti caratteri non stampabili (ad esempio immagini), mentre i moduli di testo non lo fanno quasi mai.
Dagli esempi abbiamo visto che:
multipart/form-data
: aggiunge alcuni byte di sovraccarico al confine al messaggio e deve impiegare del tempo per calcolarlo, ma invia ogni byte in un byte.
application/x-www-form-urlencoded
: ha un limite di byte singolo per campo ( &
), ma aggiunge un fattore di sovraccarico lineare di 3x per ogni carattere non stampabile.
Pertanto, anche se potessimo inviare file con application/x-www-form-urlencoded
, non vorremmo, perché è così inefficiente.
Ma per i caratteri stampabili che si trovano nei campi di testo, non importa e genera meno sovraccarico, quindi lo usiamo e basta.
%CF
è 3 byte lunghi: %
, C
e F
:-) Storia di renderlo leggibile.
nc
non accetteranno contemporaneamente sia -l
l' -p
argomento che l' argomento. Ma questo funziona per me: while true; do printf '' | nc -l 8000; done
.
Content-Type
ha due trattini ( --
) in meno, cioè quando si utilizza effettivamente il limite nel corpo del messaggio, è necessario prefissarlo --
. Inoltre, è necessario aggiungere l'ultimo limite --
, ma è abbastanza facile da notare. Vedi stackoverflow.com/questions/3508252/…
enctype='multipart/form-data
è un tipo di codifica che consente l'invio di file tramite un POST . Molto semplicemente, senza questa codifica i file non possono essere inviati tramite POST .
Se si desidera consentire a un utente di caricare un file tramite un modulo, è necessario utilizzare questo tipo di codifica .
multipart/form-data
per inviare file non binari ma è inefficiente. Credo che l'utilizzo application/x-www-form-urlencoded
sia il modo corretto per inviare dati non binari, ma qualcuno con più esperienza con i file non binari potrebbe aver bisogno di correggermi.
multipart/form-data
per l'invio di un file è che funzionerà automaticamente sia in frontend che in backend. Non è necessario eseguire alcuna gestione speciale. Tutti i file sono binari anche se devono contenere solo testo. application/x-www-form-urlencoded
è il modo standard per inviare un modulo senza file allegati. multipart/form-data
è il modo standard per inviare un modulo con file allegati. (Esistono anche numerose altre codifiche, come application/json
eapplication/json-patch+json
, che sono comuni per la comunicazione tra server e client.)
multipart/form-data
. Quello che non puoi fare è farlo usando un normale invio di moduli HTML, senza JavaScript. L'impostazione di un modulo da utilizzare multipart/form-data
è l'unico meccanismo fornito da HTML per consentire ai file POST di utilizzare JavaScript. Sento che questo non è abbastanza chiaro nella risposta e che un lettore ingenuo potrebbe pensare che l'incapacità di inviare file senza multipart/form-data
sia una limitazione di HTTP ; non è così.
Quando si invia un modulo, si comunica al proprio browser di inviare, tramite il protocollo HTTP, un messaggio sulla rete, correttamente avvolto in una struttura di messaggi del protocollo TCP / IP. Una pagina HTML ha un modo per inviare dati al server: usando <form>
s.
Quando viene inviato un modulo, viene creata e inviata una richiesta HTTP al server, il messaggio conterrà i nomi dei campi nel modulo e i valori compilati dall'utente. Questa trasmissione può avvenire con metodi HTTPPOST
o .GET
POST
dice al tuo browser di creare un messaggio HTTP e di inserire tutto il contenuto nel corpo del messaggio (un modo molto utile di fare le cose, più sicuro e anche flessibile).GET
invierà i dati del modulo nella stringa di query . Ha alcuni vincoli sulla rappresentazione e la lunghezza dei dati.L'attributo enctype
ha senso solo quando si usaPOST
metodo. Se specificato, indica al browser di inviare il modulo codificandone il contenuto in un modo specifico. Da MDN - Tipo di modulo :
Quando il valore dell'attributo del metodo è post, enctype è il tipo di contenuto MIME utilizzato per inviare il modulo al server.
application/x-www-form-urlencoded
: Questo è il valore predefinito. Quando il modulo viene inviato, vengono raccolti tutti i nomi e i valori e la codifica URL viene eseguita sulla stringa finale.multipart/form-data
: I caratteri NON sono codificati. Ciò è importante quando il modulo ha un controllo di caricamento dei file. Si desidera inviare il file binario e questo garantisce che il flusso di bit non venga modificato.text/plain
: Gli spazi vengono convertiti, ma non viene più eseguita la codifica.Quando si inviano i moduli, possono sorgere alcuni problemi di sicurezza come indicato nella Sezione 7 di RFC 7578: Dati dei moduli multipart - Considerazioni sulla sicurezza :
Tutti i software di elaborazione dei moduli devono trattare i dati dei moduli forniti dagli utenti
con sensibilità, poiché spesso contengono informazioni riservate o di
identificazione personale . Vi è un uso diffuso delle funzioni di "riempimento automatico" dei moduli nei browser Web; questi potrebbero essere utilizzati per indurre gli utenti a
inviare inconsapevolmente informazioni riservate durante il completamento di attività altrimenti
innocue. i dati multipart / form non forniscono alcuna funzionalità
per controllare l'integrità, garantire la riservatezza, evitare la
confusione dell'utente o altre funzionalità di sicurezza; tali preoccupazioni devono essere
affrontate dalle domande di compilazione e interpretazione dei moduli.Le domande che ricevono i moduli e li elaborano devono fare attenzione a non restituire dati al sito di elaborazione dei moduli richiedente che non era destinato a essere inviato.
È importante quando si interpreta il nome del file dell'intestazione Content-
Disposition per non sovrascrivere inavvertitamente i file nello
spazio file del destinatario.
Ciò ti preoccupa se sei uno sviluppatore e il tuo server elaborerà i moduli inviati dagli utenti che potrebbero finire per contenere informazioni riservate.
enctype
facciano. So che proviene letteralmente multipart/form-data
dall'RFC, ma è comunque un dump arbitrario di considerazioni sulla sicurezza relative all'invio di moduli che sono completamente ortogonali al fatto che i dati vengano inviati come application/x-www-form-urlencoded
o multipart/form-data
.
enctype='multipart/form-data'
significa che nessun carattere verrà codificato. ecco perché questo tipo viene utilizzato durante il caricamento di file sul server. Viene
quindi multipart/form-data
utilizzato quando un modulo richiede il caricamento di dati binari, come il contenuto di un file
Impostare l'attributo del metodo su POST perché il contenuto del file non può essere inserito in un parametro URL utilizzando un modulo.
Impostare il valore di enctype su multipart / form-data poiché i dati verranno suddivisi in più parti, una per ogni file più una per il testo del corpo del modulo che può essere inviato con loro.
POST
è probabilmente sufficiente per inviare un file tramite un modulo e che l'aggiunta multipart/form-data
è solo un bonus in qualche modo vago. Non è così. La maggior parte dei file richiederà assolutamente l'utilizzo multipart/form-data
.
<head>
ed <body>
è irrilevante e confusione.
Di solito questo è quando hai un modulo POST che deve prendere un caricamento di file come dati ... questo dirà al server come codificherà i dati trasferiti, in tal caso non verrà codificato perché trasferirà e caricherà i file sul server, come ad esempio quando si carica un'immagine o un pdf
L'attributo enctype specifica come codificare i dati del modulo quando lo si inoltra al server.
L'attributo enctype può essere utilizzato solo se method = "post".
Nessun carattere è codificato. Questo valore è richiesto quando si utilizzano moduli che dispongono di un controllo di caricamento dei file
Da W3Schools
multipart/form-data
. È anche abbastanza poco chiaro; cosa significa la frase "Nessun carattere codificato"? -1.