Como os parâmetros são enviados em uma solicitação HTTP POST?

1476

Em uma solicitação HTTP GET , os parâmetros são enviados como uma sequência de consultas :

http://example.com/page ? parameter = value & also = outro

Em uma solicitação HTTP POST , os parâmetros não são enviados junto com o URI.

Onde estão os valores? No cabeçalho da solicitação? No corpo da solicitação? Com o que se parece?

Camilo Martin
fonte

Respostas:

1254

Os valores são enviados no corpo da solicitação, no formato especificado pelo tipo de conteúdo.

Normalmente, o tipo de conteúdo é application/x-www-form-urlencoded, portanto, o corpo da solicitação usa o mesmo formato que a string de consulta:

parameter=value&also=another

Ao usar um upload de arquivo no formulário, você usa a multipart/form-datacodificação, que possui um formato diferente. É mais complicado, mas você geralmente não precisa se importar com o que parece, então não mostrarei um exemplo, mas pode ser bom saber que ele existe.

Guffa
fonte
25
Esqueci que os uploads de arquivos eram diferentes (+ 1 / aceito). Sua resposta é suficiente, mas seria mais agradável se tivesse mais informações multipart/form-data. Para os interessados, aqui está uma pergunta sobre isso .
Camilo Martin
73
NOTA : o corpo é separado do cabeçalho por apenas uma linha em branco .
9202 Gab Gabinete
2
Você explicou o que colocamos no HTTPBody, mas o que colocamos / escrevemos no HTTPHeader? Que finalidade serve?
Honey
4
@ Mel: O cabeçalho HTTP de uma postagem se parece com um para obter, mas com o verbo POST em vez de GET e um valor de tipo de conteúdo (e um valor opcional de comprimento do conteúdo), pois a solicitação possui conteúdo (corpo). Todo tipo de solicitação tem um cabeçalho, alguns tipos também têm um corpo.
Guffa
4
@KennethWorden Não, nenhum dos métodos enviará JSON corretamente. No entanto, pode fazer upload de um arquivo json em uma forma codificada com multipart/form-dataou se você é responsável pela construção do pedido, a mudança do tipo de conteúdo para application/jsone colar texto JSON em http corpo diretamente
Cholthi Paul Ttiopic
428

O conteúdo é colocado após os cabeçalhos HTTP. O formato de um HTTP POST é ter os cabeçalhos HTTP, seguidos por uma linha em branco, seguida pelo corpo da solicitação. As variáveis ​​POST são armazenadas como pares de valores-chave no corpo.

Você pode ver isso no conteúdo bruto de uma postagem HTTP, mostrada abaixo:

POST /path/script.cgi HTTP/1.0
From: [email protected]
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

home=Cosby&favorite+flavor=flies

Você pode ver isso usando uma ferramenta como o Fiddler , que pode ser usada para observar as solicitações de HTTP brutas e as cargas de resposta sendo enviadas através da conexão.

Joe Alfano
fonte
39
Somente se o tipo de conteúdo for application/x-www-form-urlencoded, o que nem sempre é o caso.
Guffa
@ Camilo Martin .... [+1] para uma ótima pergunta e @ Joe Alfano .... [+1] para uma ótima resposta ....... eu tenho uma idéia clara agora sobre a solicitação do POST .... mas se uma imagem vier junto com a chave, valorize o par de informações de dados ..... Como é a estrutura do POST?
Devrath
9
@ Joe, agora, por que você teria um Fromcabeçalho lá?
Pacerier 12/12/14
@ Joe, eu amo a inclusão aleatória do Fromcabeçalho. A IMO está lá em cima com o código de status HTTP 418.
Tom Howard
como você adiciona uma autenticação de usuário e senha?
m4l490n 7/01
376

Resposta curta: nas solicitações POST, os valores são enviados no "corpo" da solicitação. Nos formulários da Web, eles provavelmente são enviados com um tipo de mídia application/x-www-form-urlencodedou multipart/form-data. As linguagens de programação ou estruturas que foram concebidos para web-solicitações punho costuma fazer "a coisa certa ™" com tais pedidos e fornecer-lhe com fácil acesso aos valores facilmente decodificados (como $_REQUESTou $_POSTem PHP, ou cgi.FieldStorage(), flask.request.formem Python).


Agora vamos discordar um pouco, o que pode ajudar a entender a diferença;)

A diferença entre GETe POSTsolicitações é amplamente semântica. Eles também são "usados" de maneira diferente, o que explica a diferença de como os valores são passados.

GET ( seção RFC relevante )

Ao executar uma GETsolicitação, você solicita ao servidor uma ou um conjunto de entidades. Para permitir que o cliente filtre o resultado, ele pode usar a chamada "string de consulta" da URL. A cadeia de consulta é a parte após o ?. Isso faz parte da sintaxe do URI .

Portanto, do ponto de vista do código do aplicativo (a parte que recebe a solicitação), será necessário inspecionar a parte da consulta URI para obter acesso a esses valores.

Observe que as chaves e os valores fazem parte do URI. Os navegadores podem impor um limite no comprimento do URI. O padrão HTTP afirma que não há limite. Mas, no momento da redação deste artigo, a maioria dos navegadores não limitar os URIs (Eu não tenho valores específicos). GETAs solicitações nunca devem ser usadas para enviar novas informações ao servidor. Documentos especialmente não maiores. É aí que você deve usar POSTou PUT.

POST ( seção RFC relevante )

Ao executar uma POSTsolicitação, o cliente está realmente enviando um novo documento ao host remoto. Portanto, uma string de consulta não faz sentido (semanticamente). É por isso que você não tem acesso a eles no código do aplicativo.

POSTé um pouco mais complexo (e muito mais flexível):

Ao receber uma solicitação POST, você sempre deve esperar uma "carga útil" ou, em termos de HTTP: um corpo da mensagem . O corpo da mensagem em si é bastante inútil, pois não existe um formato padrão (tanto quanto eu sei. Talvez aplicativo / fluxo de octetos?). O formato do corpo é definido pelo Content-Typecabeçalho. Ao usar um FORMelemento HTML com method="POST", isso geralmente é application/x-www-form-urlencoded. Outro tipo muito comum é multipart / form-data se você usar uploads de arquivos. Mas poderia ser qualquer coisa , variando text/plain, acima application/jsonou até um costume application/octet-stream.

De qualquer forma, se uma POSTsolicitação for feita com uma Content-Typeque não possa ser tratada pelo aplicativo, ele deverá retornar um 415código de status .

A maioria das linguagens de programação (e / ou web-estruturas) oferecem uma maneira de de / codificar o corpo da mensagem de / para a maioria dos tipos comuns (como application/x-www-form-urlencoded, multipart/form-dataou application/json). Então é fácil. Tipos personalizados exigem potencialmente um pouco mais de trabalho.

Usando um documento codificado em formulário HTML padrão como exemplo, o aplicativo deve executar as seguintes etapas:

  1. Leia o Content-Typecampo
  2. Se o valor não for um dos tipos de mídia suportados, retorne uma resposta com um 415código de status
  3. caso contrário, decodifique os valores do corpo da mensagem.

Novamente, linguagens como PHP ou frameworks da web para outras linguagens populares provavelmente tratarão disso para você. A exceção a isso é o 415erro. Nenhuma estrutura pode prever quais tipos de conteúdo seu aplicativo escolhe para dar suporte e / ou não. Isso é com você.

PUT ( seção RFC relevante )

Uma PUTsolicitação é praticamente tratada da mesma maneira que uma POSTsolicitação. A grande diferença é que uma POSTsolicitação deve permitir que o servidor decida como (e se for o caso) criar um novo recurso. Historicamente (a partir do agora obsoleto RFC2616, era para criar um novo recurso como um "subordinado" (filho) do URI para onde a solicitação foi enviada).

Um PUTpedido em contraste é suposto "depósito" um recurso exatamente no que URI, e com exatamente esse conteúdo. Nem mais nem menos. A idéia é que o cliente seja responsável por criar o recurso completo antes de "COLOCAR" nele. O servidor deve aceitá-lo como está no URL fornecido.

Como conseqüência, uma POSTsolicitação geralmente não é usada para substituir um recurso existente. Uma PUTsolicitação pode criar e substituir.

Nota

Também existem " parâmetros de caminho " que podem ser usados ​​para enviar dados adicionais ao controle remoto, mas são tão incomuns que não entrarei em muitos detalhes aqui. Mas, para referência, aqui está um trecho da RFC:

Além dos segmentos de pontos nos caminhos hierárquicos, um segmento de caminho é considerado opaco pela sintaxe genérica. Os aplicativos produtores de URI geralmente usam os caracteres reservados permitidos em um segmento para delimitar subcomponentes específicos do esquema ou do manipulador de desreferência. Por exemplo, os caracteres reservados de ponto-e-vírgula (";") e iguais ("=") são frequentemente usados ​​para delimitar parâmetros e valores de parâmetros aplicáveis ​​a esse segmento. O caractere reservado por vírgula (",") geralmente é usado para fins semelhantes. Por exemplo, um produtor de URI pode usar um segmento como "nome; v = 1.1" para indicar uma referência à versão 1.1 de "nome", enquanto outro pode usar um segmento como "nome, 1.1" para indicar o mesmo. Os tipos de parâmetros podem ser definidos pela semântica específica do esquema,

exuma
fonte
1
Eu posso ter feito uma ligeira tangente. Adicionei um "tl; dr" na parte superior da resposta, o que deve torná-lo mais claro.
Exhuma #
Eu também agora o editei para referenciar o RFC7231 em vez do RFC2616 (que está obsoleto há algum tempo). A principal diferença para esta resposta, além dos links atualizados, está na seção "PUT".
Exhuma
Eu pensei que o PUT foi tratado de maneira diferente do POST, pois deveria ser idempotente? stackoverflow.com/questions/611906/…
rogerdpack
1
@rogerdpack Você não está errado. Se você ler o segundo parágrafo da PUTseção, verá que ele é idempotente. POSTem contraste, não pode - por definição - não ser. POSTsempre criará um novo recurso. PUTsubstituirá se um recurso idêntico existir. Portanto, se você ligar POST10 vezes, criará 10 recursos. Se você ligar PUT10 vezes, ele (talvez) criará apenas um. Isso responde à sua pergunta?
Exhuma
60

Você não pode digitá-lo diretamente na barra de URL do navegador.

Você pode ver como os dados do POST são enviados na Internet com os Cabeçalhos HTTP Ativos, por exemplo. Resultado será algo parecido

http://127.0.0.1/pass.php
POST /pass.php HTTP/1.1

Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://127.0.0.1/pass.php
Cookie: passx=87e8af376bc9d9bfec2c7c0193e6af70; PHPSESSID=l9hk7mfh0ppqecg8gialak6gt5
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
username=zurfyx&pass=password

Onde diz

Content-Length: 30
    username=zurfyx&pass=password

serão os valores da postagem.

zurfyx
fonte
2
Esclarecimento: Content-Lengthdeveria estar 29aqui? Esse é o comprimento real da string username=zurfyx&pass=password.
Hipopótamo
@ Hippo era um personagem de nova linha destinado a estar lá?
vikingsteve
@vikingsteve Entendo o que você quer dizer. Então, acho que o Conteúdo sempre tem uma nova linha no final.
Hipopótamo
2
O cabeçalho é separada do corpo com linha extra
Mára toner
24

O tipo de mídia padrão em uma solicitação POST é application/x-www-form-urlencoded. Este é um formato para codificar pares de valores-chave. As chaves podem ser duplicadas. Cada par de chave-valor é separado por um &caractere e cada chave é separada de seu valor por um =caractere.

Por exemplo:

Name: John Smith
Grade: 19

É codificado como:

Name=John+Smith&Grade=19

Isso é colocado no corpo da solicitação após os cabeçalhos HTTP.

Nejat
fonte
1
Você explicou o que colocamos no HTTPBody, mas o que colocamos / escrevemos no HTTPHeader?
Honey
Você mencionou que a chave pode ser duplicada, então qual é o resultado dessa duplicata? O último substituirá automaticamente os valores anteriores? Obrigado.
Jinghui Niu
@JinghuiNiu, se a chave estiver duplicada, ela deverá ser analisada como uma matriz. É muito tarde, mas pode ajudar outra pessoa.
Hanash Yaslem
18

Os valores do formulário nos POSTs HTTP são enviados no corpo da solicitação, no mesmo formato que a string de consulta.

Para mais informações, consulte a especificação .

SLaks
fonte
5
"Mesmo formato" é um pouco ambíguo. Eles começam com um, ?por exemplo?
Camilo Martin
7
@PeterWooster Sim, mas não fornece um exemplo. Nesse sentido, é como uma resposta que diz "veja, há uma resposta para sua pergunta no blog do aplicativo (link) ".
Camilo Martin
36
@ PeterWooster Não é necessário, mas é muito bom quando você esquece algo, pesquise no Google, vá para o primeiro link SO, e há um exemplo claro e conciso que diz o que você precisa em vez de enviá-lo para mastigar o especificações excessivamente detalhadas que, mesmo que abrangentes, podem não ser adequadas para os refrescantes. Pense bem: a maioria dos QAs neste site pode se resumir a "vá ler o spec / manual / API / etc (link) ". Seria útil? Não mais que o Google.
Camilo Martin
2
Somente se o tipo de conteúdo for application/x-www-form-urlencoded, o que nem sempre é o caso.
Guffa 27/01
3
O formato da string de consulta GET é diferente do formato application / x-www-form-urlencoded. Por exemplo, o espaço em branco é codificado de maneira diferente (% 20 vs +). A resposta é enganosa a esse respeito.
usar o seguinte código
18

Alguns dos serviços da web exigem que você coloque os dados e os metadados da solicitação separadamente. Por exemplo, uma função remota pode esperar que a sequência de metadados assinada seja incluída em um URI, enquanto os dados são postados em um corpo HTTP.

A solicitação POST pode parecer semanticamente semelhante a esta:

POST /?AuthId=YOURKEY&Action=WebServiceAction&Signature=rcLXfkPldrYm04 HTTP/1.1
Content-Type: text/tab-separated-values; charset=iso-8859-1
Content-Length: []
Host: webservices.domain.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)

name    id
John    G12N
Sarah   J87M
Bob     N33Y

Essa abordagem combina logicamente QueryString e Body-Post usando uma única Content-Typeque é uma "instrução de análise" para um servidor da web.

Observe: o HTTP / 1.1 é agrupado com o #32(espaço) à esquerda e com #10(Alimentação de linha) à direita.

Interface Desconhecida
fonte
A diferença entre /user/johne /?user=johné meramente semântica (o HTTP realmente não dá um tratamento especial às seqüências de caracteres de consulta), então eu tomo isso como razoavelmente esperado. Mas o que você quer dizer com "envolto por espaço à esquerda"? Não há espaços antes do método HTTP. Você quer dizer a linha em branco do corpo da postagem?
Camilo Martin
Há um espaço (ASCII # 32) entre ...Ym04e HTTP/1.1no código acima. Portanto, um QueryString simplesmente reside entre o verbo e a versão do protocolo.
Interface Unknown
1
Sua nota faz parecer que é algo inesperado e específico da versão. Francamente, parece óbvio que há um espaço lá. E o feed de linha também se aplica a outras linhas, como todas as coisas unix.
Camilo Martin
1
Apenas enfatizei o que não consegui marcar no código. Pode parecer óbvio, mas às vezes não é.
Interface Unknown
É verdade que poderíamos passar os parâmetros de consulta como parte da URL separando o URI e os parâmetros da ?mesma forma que fazemos com as GETsolicitações.
ASGs
8

Primeiro de tudo, vamos diferenciar entre GETePOST

Obter: é a HTTPsolicitação padrão feita ao servidor e é usada para recuperar os dados do servidor e a sequência de consultas que vem depois ?em a URIé usada para recuperar um recurso exclusivo.

este é o formato

GET /someweb.asp?data=value HTTP/1.0

aqui data=valueestá o valor da string de consulta passado.

POST: É usado para enviar dados para o servidor com segurança, para que tudo o que for necessário, este seja o formato de uma POSTsolicitação

POST /somweb.aspHTTP/1.0
Host: localhost
Content-Type: application/x-www-form-urlencoded //you can put any format here
Content-Length: 11 //it depends
Name= somename

Por que POST sobre GET?

No GETvalor enviado aos servidores, geralmente são anexados à URL base na string de consulta, agora existem duas consequências disso.

  • Os GETpedidos são salvos no histórico do navegador com os parâmetros. Portanto, suas senhas permanecem não criptografadas no histórico do navegador. Esse era um problema real para o Facebook nos dias de hoje.
  • Geralmente, os servidores têm um limite de quanto tempo URIpode ser. Se houver muitos parâmetros sendo enviados, você poderá receber414 Error - URI too long

Em caso de solicitação posterior, seus dados dos campos são adicionados ao corpo. O comprimento dos parâmetros de solicitação é calculado e adicionado ao cabeçalho para o comprimento do conteúdo e nenhum dado importante é diretamente anexado ao URL.

Você pode usar a seção de rede das Ferramentas do desenvolvedor do Google para ver informações básicas sobre como as solicitações são feitas aos servidores.

e você sempre pode adicionar mais valores em sua Request Headerscomo Cache-Control, Origin, Accept.

Zeeshan Adil
fonte
4
As suposições sobre segurança são verdadeiras apenas no contexto de uma HTTPSconexão, não HTTP. HTTPScriptografa ambos URL(incluindo parâmetros de consulta) e o Request Body, quando HTTPcriptografa / protege nenhum. O problema descrito vem do fato de muitos navegadores armazenarem o URIs(inclusive URLs) em seus bancos de dados de histórico (geralmente não criptografados). Portanto, use apenas o Request Body+ HTTPSpara qualquer coisa sensível.
Petru Zaharia
@PetruZaharia Concordo com sua explicação. Você também pode sugerir isso como edição e ficarei feliz em aceitar! :)
Zeeshan Adil