No HTTP, existem duas maneiras de colocar dados no POST: application/x-www-form-urlencoded
e multipart/form-data
. Entendo que a maioria dos navegadores só pode fazer upload de arquivos se multipart/form-data
for usada. Existe alguma orientação adicional quando usar um dos tipos de codificação em um contexto de API (nenhum navegador envolvido)? Por exemplo, isso pode ser baseado em:
- tamanho dos dados
- existência de caracteres não ASCII
- existência em dados binários (não codificados)
- a necessidade de transferir dados adicionais (como nome do arquivo)
Basicamente, não encontrei nenhuma orientação formal na Web sobre o uso dos diferentes tipos de conteúdo até o momento.
http
post
http-headers
max
fonte
fonte
Respostas:
TL; DR
Resumo; se você tiver dados binários (não alfanuméricos) (ou uma carga útil de tamanho significativo) para transmitir, use
multipart/form-data
. Caso contrário, useapplication/x-www-form-urlencoded
.Os tipos MIME mencionados são os dois
Content-Type
cabeçalhos das solicitações HTTP POST que os agentes do usuário (navegadores) devem suportar. O objetivo de ambos os tipos de solicitações é enviar uma lista de pares de nome / valor ao servidor. Dependendo do tipo e quantidade de dados transmitidos, um dos métodos será mais eficiente que o outro. Para entender o porquê, você deve examinar o que cada um está fazendo escondido.Pois
application/x-www-form-urlencoded
, o corpo da mensagem HTTP enviada ao servidor é essencialmente uma string de consulta gigante - os pares nome / valor são separados pelo e comercial (&
) e os nomes são separados dos valores pelo símbolo de igual (=
). Um exemplo disso seria:MyVariableOne=ValueOne&MyVariableTwo=ValueTwo
De acordo com a especificação :
Isso significa que, para cada byte não alfanumérico existente em um de nossos valores, serão necessários três bytes para representá-lo. Para arquivos binários grandes, triplicar a carga útil será altamente ineficiente.
É aí que
multipart/form-data
entra. Com esse método de transmissão de pares nome / valor, cada par é representado como uma "parte" em uma mensagem MIME (conforme descrito por outras respostas). As peças são separadas por um limite de cadeia específico (escolhido especificamente para que essa cadeia de limite não ocorra em nenhuma das cargas úteis de "valor"). Cada parte tem seu próprio conjunto de cabeçalhos MIMEContent-Type
, como , particularmenteContent-Disposition
, o que pode dar a cada parte seu "nome". A parte do valor de cada par nome / valor é a carga útil de cada parte da mensagem MIME. A especificação MIME nos oferece mais opções ao representar a carga útil do valor - podemos escolher uma codificação mais eficiente dos dados binários para economizar largura de banda (por exemplo, base 64 ou até binário bruto).Por que não usar
multipart/form-data
o tempo todo? Para valores alfanuméricos curtos (como a maioria dos formulários da Web), a sobrecarga de adicionar todos os cabeçalhos MIME superará significativamente qualquer economia com a codificação binária mais eficiente.fonte
LEIA PELO MENOS O PRIMEIRO PARA AQUI!
Eu sei que isso é 3 anos tarde demais, mas a resposta (aceita) de Matt está incompleta e acabará por causar problemas. A chave aqui é que, se você optar por usar
multipart/form-data
, o limite não deverá aparecer nos dados do arquivo que o servidor eventualmente receber.Isso não é um problema para
application/x-www-form-urlencoded
, porque não há limites.x-www-form-urlencoded
também pode sempre manipular dados binários, pelo simples expediente de transformar um byte arbitrário em três7BIT
bytes. Ineficiente, mas funciona (e observe que o comentário sobre a impossibilidade de enviar nomes de arquivos e dados binários está incorreto; basta enviá-lo como outro par de chave / valor).O problema
multipart/form-data
é que o separador de limites não deve estar presente nos dados do arquivo (consulte a RFC 2388 ; a seção 5.2 também inclui uma desculpa esfarrapada por não ter um tipo MIME agregado adequado que evite esse problema).Portanto, à primeira vista,
multipart/form-data
não tem valor algum em nenhum upload de arquivo, binário ou outro. Se você não escolher o seu limite corretamente, então você vai , eventualmente, ter um problema, se você está enviando texto simples ou binário simples - o servidor encontrará um limite no lugar errado, e seu arquivo será truncado, ou o POST vai falhar.A chave é escolher uma codificação e um limite para que os caracteres de limite selecionados não possam aparecer na saída codificada. Uma solução simples é usar
base64
( não use binário bruto). Na base64, 3 bytes arbitrários são codificados em quatro caracteres de 7 bits, onde o conjunto de caracteres de saída é[A-Za-z0-9+/=]
(ou seja, alfanuméricos, '+', '/' ou '=').=
é um caso especial e pode aparecer apenas no final da saída codificada, como um único=
ou um duplo==
. Agora, escolha seu limite como uma sequência ASCII de 7 bits que não pode aparecer nabase64
saída. Muitas opções que você vê na rede falham neste teste - o MDN forma docs, por exemplo, use "blob" como limite ao enviar dados binários - nada bom. No entanto, algo como "! Blob!" nunca aparecerá nabase64
saída.fonte
index === -1
.'()+-./:=
então. No entanto, a geração aleatória com substring cheque ainda é o caminho a percorrer e que pode ser feito com uma linha:while(true){r = rand(); if(data.indexOf(r) === -1){doStuff();break;}}
. A sugestão da EML (converter para base64 apenas para evitar a correspondência de substrings) é simplesmente estranha, sem mencionar que ela vem com a degradação desnecessária do desempenho. E todo o problema por nada, uma vez que o algoritmo de uma linha é igualmente direto e simples. Base64 não deve ser (ab) usado dessa maneira, pois o corpo HTTP aceita todos os octetos de 8 bits .Eu não acho que o HTTP esteja limitado ao POST em multipart ou x-www-form-urlencoded. O cabeçalho do tipo de conteúdo é ortogonal ao método HTTP POST (você pode preencher o tipo MIME que mais lhe convier). Esse também é o caso de aplicativos da Web típicos baseados em representação HTML (por exemplo, a carga útil do json se tornou muito popular para transmitir carga útil para solicitações de ajax).
Em relação à API Restful over HTTP, os tipos de conteúdo mais populares com os quais eu entrei em contato são application / xml e application / json.
application / xml:
application / json
dados binários como recurso próprio
Eu tentaria representar dados binários como ativo / recurso próprio. Ele adiciona outra chamada, mas desacopla as coisas melhor. Imagens de exemplo:
Em recursos posteriores, você pode simplesmente incorporar o recurso binário como link:
fonte
Eu concordo com muito do que Manuel disse. De fato, seus comentários se referem a este URL ...
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
... quais Estados:
No entanto, para mim, isso se resumiria ao suporte de ferramentas / estruturas.
Se você tiver uma idéia clara de seus usuários e como eles farão uso da sua API, isso ajudará você a decidir. Se você dificultar o upload de arquivos para os usuários da API, eles se afastam, e você gastará muito tempo apoiando-os.
Em segundo lugar, seria o suporte da ferramenta que você tem para escrever sua API e como é fácil acomodar um mecanismo de upload em detrimento do outro.
fonte
Apenas uma pequena dica do meu lado para fazer upload de dados de imagem em tela HTML5:
Estou trabalhando em um projeto para uma gráfica e tive alguns problemas devido ao upload de imagens para o servidor provenientes de um
canvas
elemento HTML5 . Eu estava lutando por pelo menos uma hora e não consegui salvar a imagem corretamente no meu servidor.Depois de definir a
contentType
opção da minha chamada jQuery ajax,application/x-www-form-urlencoded
tudo correu do jeito certo e os dados codificados em base64 foram interpretados corretamente e salvos com sucesso como uma imagem.Talvez isso ajude alguém!
fonte
Se você precisar usar Content-Type = x-www-urlencoded-form, NÃO use FormDataCollection como parâmetro: No asp.net Core 2+ FormDataCollection não tem construtores padrão, exigidos pelos Formadores. Use IFormCollection em vez disso:
fonte