Quando envio um formulário simples como este com um arquivo anexado:
<form enctype="multipart/form-data" action="http://localhost:3000/upload?upload_progress_id=12344" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
Choose a file to upload: <input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>
Como ele envia o arquivo internamente? O arquivo é enviado como parte do corpo HTTP como dados? Nos cabeçalhos desta solicitação, não vejo nada relacionado ao nome do arquivo.
Gostaria apenas de saber o funcionamento interno do HTTP ao enviar um arquivo.
http
file-upload
0xSina
fonte
fonte
MAX_FILE_SIZE
em PHP - que é o ponto" na stackoverflow.com/q/1381364/632951Respostas:
Vamos dar uma olhada no que acontece quando você seleciona um arquivo e envia seu formulário (truncamos os cabeçalhos por questões de brevidade):
NOTA: cada string de limite deve ser prefixada com um extra
--
, assim como no final da última string de limite. O exemplo acima já inclui isso, mas pode ser fácil perder. Veja o comentário de @Andreas abaixo.Em vez de URL que codifica os parâmetros do formulário, os parâmetros do formulário (incluindo os dados do arquivo) são enviados como seções em um documento de várias partes no corpo da solicitação.
No exemplo acima, você pode ver a entrada
MAX_FILE_SIZE
com o valor definido no formulário, bem como uma seção que contém os dados do arquivo. O nome do arquivo faz parte doContent-Disposition
cabeçalho.Os detalhes completos estão aqui .
fonte
O formato é chamado
multipart/form-data
, conforme solicitado em: O que significa enctype = 'multipart / form-data'?Eu vou:
Referências HTML5
Existem três possibilidades para
enctype
:x-www-urlencoded
multipart/form-data
(a especificação aponta para RFC2388 )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.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:
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 :Definimos o valor de texto padrão como
aωb
, o que significaaωb
porqueω
éU+03C9
, quais são os bytes61 CF 89 62
em UTF-8.Crie arquivos para upload:
Execute nosso pequeno servidor de eco:
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.multipart / form-data
Firefox enviado:
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 comnc -l localhost 8000 | hd
, que diz que os bytes:foram enviados (
61
== 'a' e62
== 'b').Portanto, é claro que:
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
define o tipo de conteúdo comomultipart/form-data
e diz que os campos são separados pelaboundary
sequência especificada .Mas observe que o:
tem dois paizinhos a menos do
--
que a barreira realIsso 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:todo campo recebe alguns subtítulos antes de seus dados:,
Content-Disposition: form-data;
o camponame
, ofilename
, 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 um limite único, 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-sequencesContent-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
enctype
paraapplication/x-www-form-urlencoded
, recarregue o navegador e reenvie.Firefox enviado:
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
eb
foram enviados em um byte, enquanto os não-imprimíveis, como0xCF
e0x89
pegou 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.
fonte
Content-Disposition
e,Content-Type
mas como lidar com o 'conteúdo'?Enviar arquivo como conteúdo binário (upload sem formulário ou FormData)
Nas respostas / exemplos fornecidos, o arquivo é (provavelmente) carregado com um formulário HTML ou usando a API FormData . O arquivo é apenas uma parte dos dados enviados na solicitação, portanto, o
multipart/form-data
Content-Type
cabeçalho.Se você quiser enviar o arquivo como o único conteúdo, poderá adicioná-lo diretamente como o corpo da solicitação e definir o
Content-Type
cabeçalho para o tipo MIME do arquivo que está enviando. O nome do arquivo pode ser adicionado noContent-Disposition
cabeçalho. Você pode fazer o upload assim:Se você (não quiser) usar formulários e estiver interessado apenas em fazer upload de um único arquivo, é a maneira mais fácil de incluir seu arquivo na solicitação.
fonte
Content-Type
o cabeçalho.Eu tenho este código Java de exemplo:
e eu tenho esse arquivo test.html:
e, finalmente, o arquivo que usarei para fins de teste, chamado a.dat, tem o seguinte conteúdo:
se você interpretar os bytes acima como caracteres ASCII ou UTF-8, eles representarão:
Então, vamos executar nosso código Java, abrir test.html em nosso navegador favorito, fazer upload
a.dat
e enviar o formulário e ver o que nosso servidor recebe:Bem, não estou surpreso ao ver os caracteres 9ie porque pedimos ao Java para imprimi-los tratando-os como caracteres UTF-8. Você também pode optar por lê-los como bytes brutos.
é realmente o último cabeçalho HTTP aqui. Depois disso, chega o Corpo HTTP, onde a meta e o conteúdo do arquivo que carregamos realmente podem ser vistos.
fonte
http://www.tutorialspoint.com/http/http_messages.htm
fonte