application/x-www-form-urlencoded ou multipart / form-data?

em HTTP há duas maneiras de postar dados: application/x-www-form-urlencoded e multipart/form-data. Eu entendo que a maioria dos navegadores só são capazes de enviar arquivos se multipart/form-data é usado. Existe alguma orientação adicional quando usar um dos tipos de codificação em um contexto API (nenhum navegador envolvido)? Isto pode, por exemplo, basear-se 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 o nome do ficheiro)

basicamente não encontrei nenhuma orientação formal na web sobre a utilização dos diferentes tipos de conteúdo até agora.

Author: max, 2010-10-24

6 answers

TL; DR

Resumo; se tiver dados binários (não alfanuméricos) (ou uma carga útil de tamanho significativo) para transmitir, use multipart/form-data. Caso contrário, utilize application/x-www-form-urlencoded.


Os tipos MIME que mencionou são os dois cabeçalhos Content-Type para os pedidos de HTTP POST que os agentes do utilizador (navegadores) têm de suportar. O objetivo de ambos os tipos de Pedidos é enviar uma lista de pares nome/valor para o servidor. Dependendo do tipo e quantidade de dados sendo transmitidos, um dos métodos será mais eficiente do que o outro. Para entender por que, você tem que olhar para o que cada um está fazendo sob os cobertores.

Para application/x-www-form-urlencoded, o corpo da mensagem HTTP enviada para o servidor é essencialmente uma cadeia de pesquisa gigante -- os pares nome/valor são separados pelo ampersand (&), e os nomes são separados dos valores pelo símbolo igual (=). Um exemplo disto seria:

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

De acordo com a especificação :

[[12]} [reservado e] os caracteres não alfanuméricos são substituídos por "% HH" , um sinal percentual e dois algarismos hexadecimais representando o código ASCII do carácter
Isso significa que para cada byte não alfanumérico que existe num dos nossos valores, serão precisos três bytes para o representar. Para grandes arquivos binários, triplicar a carga será altamente ineficiente. É aí que entra. Com este método de transmissão de pares nome/valor, cada par é representado como uma "parte" em uma mensagem MIME (como descrito por outras respostas). Partes são separadas por um limite de cadeia particular (escolhido especificamente para que esta cadeia de contorno não ocorra em nenhuma das cargas "valor"). Cada parte tem seu próprio conjunto de cabeçalhos MIME como Content-Type, e particularmente Content-Disposition, que pode dar a cada parte o seu "nome"."O valor de cada par nome / valor é a carga útil de cada parte da mensagem MIME. O spec MIME dá-nos mais opções ao representar o valor da carga útil -- podemos escolher uma codificação mais eficiente de dados binários para economizar largura de banda (por exemplo, base 64 ou mesmo binária raw).

Porque não usar {[[0]} sempre? Para valores alfanuméricos curtos (como a maioria das formas web), a sobrecarga de adicionar todos os cabeçalhos MIME vai compensar significativamente qualquer economia de codificação binária mais eficiente.

 1710
Author: Matt Bridges, 2018-02-28 22:42:45

LEIA PELO MENOS O PRIMEIRO PARÁGRAFO AQUI!

Sei que é 3 anos tarde demais, mas a resposta do Matt está incompleta e acabará por te meter em sarilhos. A chave aqui é que, se você optar por usar multipart/form-data, o limite deve Não aparecer nos dados de arquivo que o servidor eventualmente recebe.

Isto não é um problema para application/x-www-form-urlencoded, porque não há limite. x-www-form-urlencoded também pode sempre lidar com dados binários, pelo simples expediente de virar um byte arbitrário em três bytes 7BIT. Ineficiente, mas funciona (e observe que o comentário sobre não ser capaz de enviar nomes de arquivos, bem como dados binários é incorreto; você apenas envia como outro par de chaves/valores).

O problema com multipart/form-data é que o separador de limites não deve estar presente nos dados do ficheiro (ver RFC2388; a secção 5.2 também inclui uma desculpa esfarrapada para não ter um tipo MIME agregado adequado que evite este problema).

Então, à primeira vista, multipart/form-data não tem qualquer valor em qualquer arquivo upload, binário ou de outra forma. Se você não escolher o seu limite corretamente, então você eventualmente vai ter um problema, se você está enviando texto simples ou binário raw - o servidor vai 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 seus caracteres de contorno seleccionados não possam aparecer no resultado codificado. Um simples a solução deve usar base64 (do Não usar binário bruto). Em o 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+/=] (ie. alfanuméricos ou '+', '/', '='). = é um caso especial, e só pode aparecer no final da saída codificada, como um único = ou um duplo ==. Agora, Escolha o seu limite como um texto ASCII de 7 bits que não pode aparecer na saída base64. Muitas opções que você vê na net falham neste teste-as formas MDN docs , por exemplo, use "blob" como um limite ao enviar dados binários - não é bom. No entanto, algo como"!blob!"nunca aparecerá na saída base64.

 112
Author: EML, 2014-04-18 11:08:05

Não me parece que o HTTP esteja limitado a publicar em multipart ou x-www-form-urlencoded. O cabeçalho do tipo de Conteúdo é ortogonal ao método de POST HTTP (poderá preencher o tipo MIME que lhe convém). Este é também o caso de webapps típicos baseados em representação HTML (por exemplo, JSON payload tornou-se muito popular para a transmissão de carga útil para pedidos ajax).

Em relação à API repousante sobre HTTP, os tipos de conteúdo mais populares com os quais entrei em contacto são a aplicação / xml e application / json.

Application / xml:

  • tamanho dos dados: XML muito descritivo, mas geralmente não um problema quando se usa compressão e pensar que o caso de acesso de escrita (por exemplo, através de POST ou PUT) é muito mais raro do que o acesso de leitura (em muitos casos é
  • existência de caracteres não-ascii: poderá usar o utf-8 como codificação em XML
  • existência de dados binários: seria necessário usar o base64 codificação
  • dados dos nomes dos ficheiros: poderá encapsular este campo interior em XML

Application / json

  • tamanho dos dados: mais compacto menos aquele XML, texto à mesma, mas você pode comprimir
  • caracteres não ascii: json is utf-8
  • dados binários: base64 (ver também JSON-binary-question)
  • dados do nome do ficheiro: encapsular como secção própria do campo dentro do json

Dados binários como recursos próprios

Eu tentaria representar dados binários como activo/recurso próprio. Adiciona outra chamada, mas decupla melhor as coisas. Exemplo de imagens:

POST /images
Content-type: multipart/mixed; boundary="xxxx" 
... multipart data

201 Created
Location: http://imageserver.org/../foo.jpg  

Em recursos posteriores, você poderia simplesmente alinhar o recurso binário como link:

<main-resource&gt
 ...
 <link href="http://imageserver.org/../foo.jpg"/>
</main-resource>
 82
Author: manuel aldana, 2017-05-23 12:10:47
Concordo com muito do que o Manuel disse. Na verdade, seus comentários se referem a esta url...

Http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4

... que estabelece:

O tipo de conteúdo "application/x-www-form-urlencoded" is ineficiente para enviar grandes quantidades de dados binários ou texto que contenham caracteres não ASCII. O tipo de conteúdo "multipart / form-data" devem ser utilizados para a apresentação de formulários que contêm ficheiros, não-ASCII dado, e dados binários.

No entanto, para mim, tudo se resumiria ao suporte de ferramentas/framework.
  • que Ferramentas e enquadramentos faz você espere que seus usuários da API estejam construindo as aplicações deles?
  • Eles têm frameworks ou componentes que podem usar que favorecem um método sobre o outro?

Se você tiver uma ideia clara de seus usuários, e como eles vão fazer uso de sua API, então isso vai ajudá-lo a decidir. Se tornar o envio de ficheiros difícil para os utilizadores da API depois eles vão-se embora, de TI vais passar muito tempo a apoiá-los.

Secundário a isso seria o Suporte de ferramenta que você tem para escrever a sua API e como é fácil para você acomodar um mecanismo de upload sobre o outro.

 26
Author: Martin Peck, 2012-05-03 14:53:57

Apenas uma pequena dica do meu lado para carregar os dados da imagem de tela do HTML5:

Estou a trabalhar num projecto para uma tipografia e tive alguns problemas devido ao envio de imagens para o servidor que vieram de um elemento HTML5 {[[0]}. Eu estava lutando por pelo menos uma hora e eu não consegui para salvar a imagem corretamente no meu servidor.

Uma vez que eu pus o ... A opção da minha chamada para o jQuery ajax correu tudo bem e os dados codificados no base64 foram interpretados correctamente e ... gravado com sucesso como uma imagem.
Talvez isso ajude alguém!
 0
Author: Torsten Barthel, 2016-12-22 10:10:02

Se necessitar de utilizar o Content-Type=x-www-urlencoded-form então não utilize FormDataCollection como parâmetro: em asp.net Core 2+ FormDataCollection has no default constructors which is required by Formatters. Utilize a recolha de dados IFormCollection em vez disso:

 public IActionResult Search([FromForm]IFormCollection type)
    {
        return Ok();
    }
 0
Author: jahansha, 2018-10-02 18:52:24