Mensagens HTTP são escritas em texto
simpes e seguem um
formato geral, válido tanto para requisições, quanto para
respostas. Antes de entrarmos em maiores detalhes, vejamos dois
exemplos simples de mensagens HTTP. Primeiro, um exemplo de
requisição. O request abaixo pode ser usado para solicitar ao
servidor www.dsc.ufcg.edu.br o recurso /~dalton/exemplo.txt,
usando o protocolo HTTP/1.1.
GET /~dalton/exemplo.txt HTTP/1.1
Host: www.dsc.ufcg.edu.br
Abaixo um exemplo de uma resposta ou response HTTP. De fato, este é o response que recebi do servidor mencionado acima, como resposta ao request acima.
HTTP/1.1 200 OK
Date: Sat, 31 Aug 2019 21:41:02 GMT
Server: Apache/2.4.37 (Unix) PHP/5.6.39
Last-Modified: Sat, 31 Aug 2019 21:37:42 GMT
ETag: "8f-591708c7df108"
Accept-Ranges: bytes
Content-Length: 143
Content-Type: text/plain
Exemplo de arquivo de texto disponível como recurso
na Web. Para acessá-lo, use o endereço:
http://www.dsc.ufcg.edu.br/~dalton/exemplo.txt
Mensagens HTTP seguem um formato geral único que consiste em 4 partes:
Observação. Todas as linhas da mensagem devem ser terminadas por uma sequência conhecida como CRLF que consite em um caractere de carriage return (
\r) e um caractere de line feed (\n). Isso inclui a linha em branco depois dos cabeçalhos.
Cabeçalhos Os cabeçalhos são usados para que cliente e
servidor possam trocar dados complementares, necessários para o
protocolo. Cada cabeçalho é um par nome, valor. O formato de cada
linha de cabeçalho consiste no nome do cabeçalho
(case-insensitive), seguido do caractere :, espaços em branco
opcionais, o valor do cabeçalho e espaços em branco opcionais.
Em uma requisição HTTP/1.1, há um único cabeçalho obrigatório:
Host. Ele deve ser usado para indicar o domínio a que se refere a requisição. É necessário porque uma mesmo servidor pode hospedar múltiplos domínios (os chamados domínios virtuais).
O corpo Tipicamente, o corpo é usado por responses para transmitir os dados solicitados pelo usuário. Assim, tipicamente, requests têm, um corpo vazio. Veremos mais adiante, contudo, que há requests que precisam incluir dados no corpo da mensagem. Isso ocorre quando o cliente precisa enviar dados do usuário para o servidor.
Observe as mensagens exemplos acima. Identifique nelas as várias partes das mensagens: a linha inicial, os cabeçalhos, a linha em branco e o corpo. Identifique os cabeçalhos usados e seus valores. Também observe a linha em branco colocada logo após os cabeçalhos. No caso do response, a linha em branco fica bastante evidente. No request a linha em branco também está lá, embora não seja tão fácil percebê-la, porque não há nada depois dela, na mensagem.
O único elemento sintático que diferencia uma requisição (request) de uma resposta (response) HTTP é a linha inicial. Requisições usam um formato de linha inicial chamado request line e respostas usam o formato status line. Vejamos cada um dos formatos.
O request line A linha inicial de uma requisição sempre consiste em três elementos separados por um espaço, denominados: método, alvo da requisição e versão do HTTP. O request line de nosso exemplo acima é destacado abaixo. Identifique nele cada uma das partes mencionadas.
GET /~dalton/exemplo.txt HTTP/1.1
O status line A linha inicial de uma resposta consiste em três elementos, separados por um espaço, denominados: versão do HTTP, código de status (ou status code) e a frase de motivo (ou _reason-phrase), sendo esta última opcional. O status code é um código de três digitos que resume o resultado do processamento da requisição. Todos os dados contidos no response, incluindo os cabeçalhos e o corpo, são interpretados a partir da semântica associada ao status code. A frase de motivo, que é opcional, é uma mera descrição textual que descreve o status code, incluída exclusivamente para tornar o response mais legível. O status line de nosso exemplo acima é destacado abaixo. Identifique nele cada uma das partes mencionadas.
HTTP/1.1 200 OK
É importante desenvolver um entendimento detalhado do que ocorre quando fazemos requisições através de um browser ou outros aplicativos que operem como clientes web. Para isso, contudo, o melhor é fazermos algumas poucas requisições, diretamente através de um socket e uma conexão TCP.
Para isso, usaremos o aplicativo netcat que já usamos na lição sobre sockets e conexões TCP. Relembre que netcat nos permite criar uma conexão TCP para um servidor e que, uma vez estabelecida a conexão, nos permitirá enviar e receber bytes através da conexão. Se executarmos o netcat como indicado no comando abaixo, poderemos escrever o request manualmente.
nc -c www.dsc.ufcg.edu.br 80
O comando acima faz netcat criar uma conexão ao servidor de
nome www.dsc.ufcg.edu.br na porta 80 que é a porta padrão de
servidores HTTP. Observe que usei o parâmetro -c que, no
netcat do MacOs, pede que todos os \n sejam devidamente
substituídos por \r\n, garantindo que o protocolo HTTP seja
atendido.
O vídeo abaixo mostra como o comando pode ser usado para fazer
requisições semelhantes às do exemplo acima. No mesmo vídeo,
quatro requisições são feitas, sendo que apenas a primeira com
sucesso. Relembre que o cabeçalho Host é o único obrigatório
em HTTP/1.1. Observe como o servidor responde cada requisição.

Faça você mesmo requisições, usando netcat, via linha de comando. Observe que o comando pode ser
ncounetcat, a depender do sistema que você está usando. No MacOS o argumento para fazer o netcat usar CRLF ao final de cada linha é-c. No Linux, contudo, é-C(ou--crlf). Se não funcionar, veja o manual do netcat, com o comandoman ncouman netcat.
A semântica de HTTP (1.1) é definida pelo RFC 7231. Por semântica entende-se o significado das mensagens. O documento define, portanto, como o servidor e o cliente devem interpretar requests e responses, respectivamente. Claramente, são informações essenciais para o desenvolvimento de user-agents e de origin-servers. Como este curso é focado no desenvolvimento de aplicações web, contudo, precisamos apenas de um entendimento dos conceitos básicos e não de detalhes. Além disso, como, ao vermos a sintaxe de HTTP já tratamos o essencial da semântica de requisições, nesta seção focaremos na semântica de responses.
Relembre que a sintaxe de responses consiste numa primeira
linha denominada status line. Nessa linha, o item de maior
importância é o status code (segundo elemento da linha). Os
status codes pertencem a uma de cinco classes. O primeiro
digito do status code indica a classe a que o status code
pertence e determina a semântica geral do response. Há cinco
classes de status codes, indicadas pelos digitos de 1 a 5.
Cada classe agrupa vários status codes que compartilham o mesmo
significado abstrato da classe. O protocolo não exige que os
clientes saibam como interpretar cada um dos inúmeros status
codes existentes, mas exige que saibam interpretar a classe a
que pertencem. Por regra, se um cliente recebe um status code
que desconhece, digamos 468, então ele deve reagir apenas
baseado na classe. Neste caso, deve tratar o código como se fosse
400. Em todas as classes, o código x00 é reservado para
expressar o significado mais geral da classe. Da forma análoga,
se o desenvolvedor do servidor não sabe o status code exato a
usar para determinada situação, é necessário que saiba ao menos
escolher a classe correta de status code e, nesse caso, que use
o código geral x00. As cinco classes e seus significados são
descritas a seguir.
Um excelente site que uso sempre que preciso escolher o status code apropriado para uma dada situação é o do REST API Tutorial. O mesmo site contém bastante material sobre REST (o que não deixa de ser sobre conceitos HTTP).
Respostas desta classe são respostas provisórias e indicam o andamento do processamento da requisição. São usadas pelo servidor para indicar que a requisição foi recebida e que está sendo processada. Tipicamente, outra resposta pode ser esperada pelo cliente. Em geral, o desenvolvedor de aplicações web não irá lidar com responses com este tipo de mensagem, porque são tratadas silenciosamente pelo browser.
O código
100, cuja reason-phrase é Continue, indica apenas que a parte inicial do request foi recebida e que, até o momento do response, não havia sido rejeitada e está sendo processada.
Respostas desta classe indicam que a requisição
requisição foi recebida, compreendida
e atendida com sucesso. A classe contém vários códigos para
diferentes tipos de ações como o 201 (Created) e 202
(Accepted).
O status-code
200, cujo reason-phrase é Ok, indica que a requisição foi recebida, processada e atendida com sucesso.
Respostas desta classe indicam que o cliente precisa fazer uma nova ação para obter o recursos desejado. Tipicamente, isso pode implicar em: fazer uma nova requisição, usando um endereço diferente; escolher entre múltiplas opções de endereços; reusar uma versão do recurso baixada anteriormente (útil para as chamadas requisições condicionais).
O status-code
300, cujo reason-phrase é Multiple Choices, indica que o recurso indicado na requisição corresponde a múltiplas representações e que o cliente deve optar por uma. Em vários casos, a nova requisição é feita automaticamente pelo browser.
Respostas desta classe indicam que o servidor não atendeu à
requisição e que entende que isso ocorre devido a um erro na
requisição, por parte do cliente. Dentre os códigos mais conhecidos e
usados estão os famosos 401 (Unauthorized) e 404 (Not found),
além de 403 (Forbidden) e 409 (Conflict).
O status-code
400, cujo reason-phrase é Bad Request, indica que o servidor não pode ou não vai processar a requisição devido a algum erro atribuído ao servidor (isso inclui desde erros de sintaxe na mensagem a problemas com autenticação e erros lógicos relativos a restrições em nível de aplicação para o recurso).
Respostas desta classe indicam que o servidor encontrou alguma
situação inesperada que o impediu de atender à requisição. Ao
contrário da classe anterior, neste caso, a resposta indica que a
requisição foi devidamente compreendida, mas que o servidor não
pode processar e/ou atender à requisição. Pode indicar
erros de lógica, falhas de hardware, indisponibilidade de certos
recursos, etc. Dentre os códigos mais conhecidos e usados, estão o 501
(Not Implemented) e o 503 (Service Unavailable).
O status-code
500, cuja reason-phrase é Internal Server Error, indica apenas que o servidor se deparou com uma condição interna inesperada que o impediu de atender à requisição.