Respostas:
Quando você faz uma solicitação POST, é necessário codificar os dados que formam o corpo da solicitação de alguma maneira.
Os formulários HTML fornecem três métodos de codificação.
application/x-www-form-urlencoded
(o padrão)multipart/form-data
text/plain
O trabalho estava sendo feito para adicionar application/json
, mas isso foi abandonado.
(Outras codificações são possíveis com solicitações HTTP geradas usando outros meios que não o envio de um formulário HTML. JSON é um formato comum para uso com serviços da Web e alguns ainda usam SOAP.)
As especificidades dos formatos não importam para a maioria dos desenvolvedores. Os pontos importantes são:
text/plain
.Ao escrever código do lado do cliente:
multipart/form-data
quando seu formulário incluir qualquer <input type="file">
elementomultipart/form-data
ou application/x-www-form-urlencoded
mas application/x-www-form-urlencoded
será mais eficienteQuando você está escrevendo o código do servidor:
A maioria (como o Perl CGI->param
ou o exposto pela $_POST
superglobal do PHP ) cuidará das diferenças para você. Não se preocupe em tentar analisar a entrada bruta recebida pelo servidor.
Às vezes, você encontrará uma biblioteca que não pode lidar com os dois formatos. A biblioteca mais popular do Node.js. para manipular dados do formulário é o analisador de corpo que não pode lidar com solicitações de várias partes (mas possui documentação que recomenda algumas alternativas que podem).
Se você estiver gravando (ou depurando) uma biblioteca para analisar ou gerar os dados brutos, precisará começar a se preocupar com o formato. Você também pode querer saber sobre isso por interesse.
application/x-www-form-urlencoded
é mais ou menos o mesmo que uma string de consulta no final do URL.
multipart/form-data
é significativamente mais complicado, mas permite que arquivos inteiros sejam incluídos nos dados. Um exemplo do resultado pode ser encontrado na especificação HTML 4 .
text/plain
é introduzido pelo HTML 5 e é útil apenas para depuração - a partir das especificações : eles não são interpretáveis de maneira confiável por computador - e eu argumentaria que os outros combinados com ferramentas (como o Painel de Rede nas ferramentas de desenvolvedor da maioria dos navegadores) são melhores por isso).
quando devemos usá-lo
A resposta de Quentin está correta: use multipart/form-data
se o formulário contiver um upload de arquivo e application/x-www-form-urlencoded
, caso contrário, qual será o padrão se você omitir enctype
.
Eu vou:
Existem três possibilidades para enctype
:
application/x-www-form-urlencoded
multipart/form-data
(a especificação aponta para RFC7578 )text/plain
. Isso "não é interpretável de maneira confiável pelo computador", portanto nunca deve ser usado na produção e não iremos mais investigá-lo.Depois de ver um exemplo de cada método, fica óbvio como eles funcionam e quando você deve usar cada um.
Você pode produzir exemplos usando:
nc -l
ou um servidor ECHO: servidor de teste HTTP que aceita solicitações GET / POSTSalve o formulário em um .html
arquivo mínimo :
<!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>
Definimos o valor de texto padrão como aωb
, o que significa aωb
porque ω
é U+03C9
, quais são os bytes 61 CF 89 62
em UTF-8.
Crie arquivos para upload:
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
Execute nosso pequeno servidor de eco:
while true; do printf '' | nc -l 8000 localhost; done
Abra o HTML no seu navegador, selecione os arquivos, clique em enviar e verifique o terminal.
nc
imprime a solicitação recebida.
Testado em: Ubuntu 14.04.3, nc
BSD 1.105, Firefox 40.
Firefox enviado:
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--
Para o arquivo binário e o campo de texto, os bytes 61 CF 89 62
( aωb
em UTF-8) são enviados literalmente. Você pode verificar isso com nc -l localhost 8000 | hd
, que diz que os bytes:
61 CF 89 62
foram enviados ( 61
== 'a' e 62
== 'b').
Portanto, é claro que:
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
define o tipo de conteúdo como multipart/form-data
e diz que os campos são separados pela boundary
sequência especificada .
Mas observe que o:
boundary=---------------------------735323031399963166993862150
tem dois paizinhos a menos do --
que a barreira real
-----------------------------735323031399963166993862150
Isso ocorre porque o padrão requer que o limite comece com dois traços --
. Os outros traços parecem ser exatamente como o Firefox escolheu implementar o limite arbitrário. A RFC 7578 menciona claramente que esses dois traços principais --
são necessários:
4.1 Parâmetro "Limite" de dados de várias partes / formulário
Como em outros tipos de várias partes, as partes são delimitadas com um delimitador de limite, construído usando CRLF, "-" e o valor do parâmetro "limite".
todo campo recebe alguns subtítulos antes de seus dados:, Content-Disposition: form-data;
o campo name
, o filename
, seguido pelos dados.
O servidor lê os dados até a próxima sequência de limites. O navegador deve escolher um limite que não apareça em nenhum dos campos; é por isso que o limite pode variar entre solicitações.
Como temos o limite exclusivo, nenhuma codificação dos dados é necessária: dados binários são enviados como estão.
TODO: qual é o tamanho ideal do limite ( log(N)
aposto) e o nome / tempo de execução do algoritmo que o encontra? Perguntado em: /cs/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequences
Content-Type
é determinado automaticamente pelo navegador.
Como foi determinado exatamente foi perguntado em: Como o tipo MIME de um arquivo carregado é determinado pelo navegador?
Agora mude enctype
para application/x-www-form-urlencoded
, recarregue o navegador e reenvie.
Firefox enviado:
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
Claramente, os dados do arquivo não foram enviados, apenas os nomes de base. Portanto, isso não pode ser usado para arquivos.
Como para o campo de texto, vemos que caracteres imprimíveis habituais, como a
e b
foram enviados em um byte, enquanto os não-imprimíveis, como 0xCF
e 0x89
pegou 3 bytes cada um: %CF%89
!
O upload de arquivos geralmente contém muitos caracteres não imprimíveis (por exemplo, imagens), enquanto os formulários de texto quase nunca o fazem.
A partir dos exemplos, vimos que:
multipart/form-data
: adiciona alguns bytes de sobrecarga de limite à mensagem e deve passar algum tempo calculando-a, mas envia cada byte em um byte.
application/x-www-form-urlencoded
: possui um limite de byte único por campo ( &
), mas adiciona um fator de sobrecarga linear de 3x para cada caractere não imprimível.
Portanto, mesmo se pudéssemos enviar arquivos application/x-www-form-urlencoded
, não desejaríamos, porque é muito ineficiente.
Porém, para caracteres imprimíveis encontrados em campos de texto, isso não importa e gera menos sobrecarga; portanto, apenas o usamos.
%CF
é de 3 bytes de comprimento: %
, C
e F
:-) História de torná-lo legível.
nc
não aceita -l
os -p
argumentos e os simultaneamente. Mas isso funciona para mim: while true; do printf '' | nc -l 8000; done
.
Content-Type
possui dois hífens ( --
) a menos, ou seja, ao usar o limite no corpo da mensagem, você deve prefixá-lo --
. Além disso, o último limite deve ter o sufixo --
, mas isso é fácil de notar. Veja stackoverflow.com/questions/3508252/…
enctype='multipart/form-data
é um tipo de codificação que permite que arquivos sejam enviados por meio de um POST . Simplesmente, sem essa codificação, os arquivos não podem ser enviados pelo POST .
Se você deseja permitir que um usuário faça upload de um arquivo por meio de um formulário, use este enctype .
multipart/form-data
para enviar arquivos não binários, mas é ineficiente. Acredito que usar application/x-www-form-urlencoded
é a maneira correta de enviar dados não binários, mas alguém com mais experiência com arquivos não binários pode precisar me corrigir.
multipart/form-data
envio de um arquivo é que ele funcionará automaticamente no front-end e no back-end. Você não precisa fazer nenhum tratamento especial. Todos os arquivos são binários, mesmo que devam conter apenas texto. application/x-www-form-urlencoded
é a maneira padrão de POSTAR um formulário sem os arquivos anexados. multipart/form-data
é a maneira padrão de POSTAR um formulário com os arquivos anexados. (Há também inúmeras outras codificações, como application/json
e application/json-patch+json
, que são comuns para a comunicação entre o servidor eo cliente.)
multipart/form-data
. O que você não pode fazer é fazer isso usando um envio de formulário HTML comum, sem JavaScript. A configuração de um formulário a ser usado multipart/form-data
é o único mecanismo que o HTML fornece para permitir que você POST arquivos sem usar JavaScript. Sinto que isso não está claro o suficiente na resposta e que um leitor ingênuo pode pensar que a incapacidade de enviar arquivos sem multipart/form-data
é uma limitação do HTTP ; Esse não é o caso.
Ao enviar um formulário, você instrui seu navegador a enviar, através do protocolo HTTP, uma mensagem na rede, adequadamente envolvida em uma estrutura de mensagem do protocolo TCP / IP. Uma página HTML tem uma maneira de enviar dados para o servidor: usando <form>
s.
Quando um formulário é enviado, uma solicitação HTTP é criada e enviada ao servidor, a mensagem conterá os nomes dos campos no formulário e os valores preenchidos pelo usuário. Essa transmissão pode ocorrer com os métodosPOST
ou GET
HTTP .
POST
informa ao navegador para criar uma mensagem HTTP e colocar todo o conteúdo no corpo da mensagem (uma maneira muito útil de fazer as coisas, mais segura e também flexível).GET
enviará os dados do formulário na string de consulta . Tem algumas restrições sobre a representação e o comprimento dos dados.O atributo enctype
só faz sentido ao usar o POST
método Quando especificado, ele instrui o navegador a enviar o formulário, codificando seu conteúdo de uma maneira específica. Do MDN - Tipo de formulário :
Quando o valor do atributo do método é post, enctype é o tipo de conteúdo MIME usado para enviar o formulário ao servidor.
application/x-www-form-urlencoded
: Esse é o padrão. Quando o formulário é enviado, todos os nomes e valores são coletados e a codificação de URL é executada na sequência final.multipart/form-data
: Os caracteres NÃO são codificados. Isso é importante quando o formulário possui um controle de upload de arquivo. Você deseja enviar o arquivo binário e isso garante que o fluxo de bits não seja alterado.text/plain
: Os espaços são convertidos, mas não é mais realizada codificação.Ao enviar formulários, podem surgir algumas preocupações de segurança, conforme declarado na Seção 7 da RFC 7578: Dados de formulário de várias partes - Considerações de segurança :
Todo software de processamento de formulários deve tratar os dados do formulário fornecidos pelo usuário
com sensibilidade, pois geralmente contém informações confidenciais ou de
identificação pessoal . Há amplo uso dos recursos de preenchimento automático de formulários nos navegadores da Web; elas podem ser usadas para induzir os usuários a
enviar informações confidenciais sem saber ao concluir
tarefas que de outra forma seriam inócuas. multipart / form-data não fornece nenhum recurso
para verificar a integridade, garantir a confidencialidade, evitar
confusão do usuário ou outros recursos de segurança; essas preocupações devem ser
tratadas pelos aplicativos de preenchimento de formulários e de interpretação de dados de formulários.Os aplicativos que recebem formulários e os processam devem ter cuidado para não fornecer dados de volta ao site solicitante de processamento de formulários que não deveria ser enviado.
É importante, ao interpretar o nome do arquivo do
campo de cabeçalho Content- Disposition, não substituir arquivos inadvertidamente no
espaço no arquivo do destinatário.
Isso se preocupa se você é um desenvolvedor e seu servidor processa os formulários enviados pelos usuários que podem acabar contendo informações confidenciais.
enctype
fazer. Eu sei que é literalmente da multipart/form-data
RFC, mas, no entanto, é um despejo arbitrário de considerações de segurança sobre o envio de formulários inteiramente ortogonais para o envio application/x-www-form-urlencoded
ou não de dados multipart/form-data
.
enctype='multipart/form-data'
significa que nenhum caractere será codificado. é por isso que esse tipo é usado durante o upload de arquivos para o servidor.
Então, multipart/form-data
é usado quando um formulário requer dados binários, como o conteúdo de um arquivo, para ser carregado
Defina o atributo do método como POST porque o conteúdo do arquivo não pode ser colocado dentro de um parâmetro de URL usando um formulário.
Defina o valor de enctype como multipart / form-data porque os dados serão divididos em várias partes, uma para cada arquivo e outra para o texto do corpo do formulário que pode ser enviado com eles.
POST
é provável que seja suficiente para enviar um arquivo por meio de um formulário e que adicionar multipart/form-data
é apenas um bônus de alguma maneira vaga. Esse não é o caso. A maioria dos arquivos exigirá absolutamente o uso multipart/form-data
.
<head>
e <body>
é irrelevante e confuso.
Geralmente é quando você tem um formulário POST que precisa fazer o upload de um arquivo como dados ... isso informa ao servidor como ele codificará os dados transferidos; nesse caso, ele não será codificado porque apenas transferirá e fará o upload os arquivos para o servidor, como, por exemplo, ao fazer upload de uma imagem ou pdf
O atributo enctype especifica como os dados do formulário devem ser codificados ao enviá-los ao servidor.
O atributo enctype pode ser usado apenas se method = "post".
Nenhum caractere é codificado. Este valor é necessário quando você está usando formulários que possuem um controle de upload de arquivo
De W3Schools
multipart/form-data
. Também não é muito claro; o que significa a frase "Nenhum caractere é codificado"? -1.