O que significa enctype = 'multipart / form-data'?

Respostas:

1570

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:

  • Nunca use text/plain.

Ao escrever código do lado do cliente:

  • use multipart/form-dataquando seu formulário incluir qualquer <input type="file">elemento
  • caso contrário, você pode usar multipart/form-dataou application/x-www-form-urlencodedmas application/x-www-form-urlencodedserá mais eficiente

Quando você está escrevendo o código do servidor:

  • Use uma biblioteca de manipulação de formulário pré-escrita

A maioria (como o Perl CGI->paramou o exposto pela $_POSTsuperglobal 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).

Quentin
fonte
5
@ Quentin Com licença, qual será o provável problema se usarmos multipart para todos os formulários? com e sem arquivos.
Webinan
12
Não faz sentido para os formulários GET e aumenta o tamanho do arquivo das solicitações.
Quentin
@Quentin os dados do formulário de várias partes são enviados como um fluxo por padrão?
Growler
O enc in enctype representa alguma coisa?
Philip Rego
1
"Os formulários HTML fornecem três métodos de detecção de ENC "
Quentin
449

quando devemos usá-lo

A resposta de Quentin está correta: use multipart/form-datase 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:

  • adicione mais algumas referências HTML5
  • explicar por que ele está certo com um exemplo de envio de formulário

Referências HTML5

Existem três possibilidades para enctype:

Como gerar os exemplos

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:

Salve o formulário em um .htmlarquivo 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&#x03C9;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&#x03C9;b, o que significa aωbporque ωé U+03C9, quais são os bytes 61 CF 89 62em 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, ncBSD 1.105, Firefox 40.

multipart / form-data

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ωbem 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=---------------------------735323031399963166993862150define o tipo de conteúdo como multipart/form-datae diz que os campos são separados pela boundarysequê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?

application / x-www-form-urlencoded

Agora mude enctypepara 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 ae bforam enviados em um byte, enquanto os não-imprimíveis, como 0xCFe 0x89pegou 3 bytes cada um: %CF%89!

Comparação

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.

Ciro Santilli adicionou uma nova foto
fonte
3
@ Khanna111 %CFé de 3 bytes de comprimento: %, Ce F:-) História de torná-lo legível.
Ciro Santilli publicou 6/08/15
6
No OS X, ncnão aceita -los -pargumentos e os simultaneamente. Mas isso funciona para mim: while true; do printf '' | nc -l 8000; done.
precisa saber é
4
Um ponto pequeno, mas importante, que não é mencionado, é que o limite especificado em Content-Typepossui 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/…
Bernard
1
Até onde eu sei, o objetivo de colocar QUALQUER DASH DASTES NO limite é tornar impossível verificar a sintaxe da solicitação a olho nu. Por favor, não os use em seus tokens de limite.
Dewi Morgan
1
@DewiMorgan Você está completamente certo. Editei a postagem e removi os traços da string de limite.
Max
91

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 .

Matt Asbury
fonte
Então .. se o arquivo não é um arquivo binário, podemos trabalhar sem isso?
Yugal Jindle
Pelo que entendi, você pode usar multipart/form-datapara 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.
Matt Asbury
11
A principal vantagem do multipart/form-dataenvio 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/jsone application/json-patch+json, que são comuns para a comunicação entre o servidor eo cliente.)
Daniel Luna
6
Vale ressaltar que você pode codificar base64 sua imagem e enviá-la como dados simples de sequência.
James
3
Além do comentário de @ Prospero acima: você pode absolutamente enviar arquivos via POST sem usar 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.
Mark Amery
81

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).
  • GETenviará os dados do formulário na string de consulta . Tem algumas restrições sobre a representação e o comprimento dos dados.

Declarando como enviar seu formulário para o servidor

O atributo enctypesó faz sentido ao usar o POSTmé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.

Segurança

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.

Andry
fonte
1
O material sobre segurança após a edição mais recente é irrelevante para a questão do que enctypefazer. Eu sei que é literalmente da multipart/form-dataRFC, 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-urlencodedou não de dados multipart/form-data.
Mark Amery
38

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

GP Singh
fonte
8

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.

arenoso
fonte
Isso implica que 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.
underscore_d
1
  • O atributo enctype ( ENC ode TYPE ) especifica como os dados do formulário devem ser codificados ao enviá-los ao servidor.
  • multipart / form-data é um dos valores do atributo enctype, usado no elemento do formulário que possui um upload de arquivo. multi-part significa que os dados do formulário se dividem em várias partes e são enviados ao servidor.
Premraj
fonte
5
Eu acredito que enctype não representa o tipo de criptografia. Não há criptografia envolvida neste nível. Meu palpite é o tipo de codificação ou o tipo fechado. Mas certamente não é do tipo de criptografia.
Yeo
1
Seu ponto de bala final aqui sobre <head>e <body>é irrelevante e confuso.
Mark Amery
0

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

Eric
fonte
-3

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

Rishad
fonte
2
Esta citação nem sequer menciona multipart/form-data. Também não é muito claro; o que significa a frase "Nenhum caractere é codificado"? -1.
Mark Amery