O protocolo HTTP – Parte 1
Todo profissional web conhece o protocolo mais famoso da Internet, o HTTP, mas muitos não utilizam todos os recursos e features que ele oferece. Nos próximos posts, eu pretendo explorar vários aspectos desse protocolo que está presente em todas as aplicações da web, e fazer os desenvolvedores olharem para seus sistemas com outros olhos.
Breve descrição do HTTP
HTTP, ou Hipertext Transfer Protocol, é um protocolo de rede situado na camada de aplicação do Modelo OSI, normalmente implementado sobre TCP/IP, que tem por objetivo permitir a troca de dados em sistemas distribuídos, dados esses geralmente chamados de hiperdocumentos, sendo o HTML o mais conhecido. Os sistemas que utilizam o HTTP geralmente possuem arquitetura cliente/servidor, ou seja, existe um cliente (browser) que faz a requisição a um servidor (servidor web) que por sua vez fornece os dados requisitados pelo cliente, sem manter informações de estado entre uma requisição e outra. O cliente informa o documento que deseja recuperar através de URIs, ou mais especificamente, de URLs.
A capacidade do protocolo de acessar e interligar hiperdocumentos foi fundamental para o surgimento da World Wide Web, por volta de 1990. O criador desse protocolo (e consequentemente, da web) é o mestre Tim Berners-Lee, aquele tiozinho parecido com o Sting ali em cima. Hoje, dentre outras coisas legais, ele é o diretor do W3C.
O protocolo HTTP já passou por algumas revisões, a última resultando na versão HTTP/1.1, publicada na W3C em 1997 e revisada em 1999, e usada até hoje. Da versão 1.0 para a 1.1 do HTTP, a melhoria mais significativa foi a introdução da capacidade de fazer conexões permanentes entre cliente e servidor, reaproveitando a mesma conexão para transmitir imagens, texto e outros elementos dos hiperdocumentos. Isso tornou a transferência de dados entre cliente e servidor muito mais rápida, pois elimina a sobrecarga de abrir uma conexão TCP para cada requisição do cliente.
Nesse primeiro post, vou abordar uma das principais funções do protocolo: as requisições e seus diferentes métodos.
HTTP Requests
Uma requisição feita por um cliente (browser, por exempl0) no protocolo HTTP, é formada da seguinte maneira:
- A primeira linha da mensagem contém o caminho do recurso solicitado, por exemplo:
GET /blog/post.html HTTP/1.1
- A seguir, são especificados os headers (cabeçalhos) da mensagem.
Host: www.brunofajardo.com
- Os headers são seguidos por uma linha em branco, que deve ser formada somente pelos caracteres CR (carriage return) e LF (line feed);
- Depois dessa linha, o conteúdo é opcional. O que estiver aqui será interpretado pelo servidor dependendo do método HTTP executado.
HTTP Methods
Existem oito métodos diferentes no protocolo HTTP, e eles representam ações que o cliente pode realizar sobre um recurso (hiperdocumento) do servidor.
GET
É utilizado para recuperar uma “cópia” do endereço especificado no cabeçalho. Esse método é o mais comum do HTTP, executado quando se digita uma URL em um browser. O servidor retorna um cabeçalho contendo informações sobre o documento, além do corpo da mensagem (uma página HTML, por exemplo).
A fim de diminuir o tráfego de dados desnecessários na rede, é possível realizar um “GET condicional”, ou seja, somente recuperar o documento solicitado quando algumas condições, especificadas no cabeçalho da requisição, forem satisfeitas. Alguns dos cabeçalhos que podem ser utilizados para isso são If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match, e If-Range. O cabeçalho Range pode ser utilizado para recuperar somente uma parte do documento, para fins de economia de banda também.
POST
Envia dados para serem processados no servidor pelo recurso que foi endereçado. Geralmente, quando você preenche um formulário na web, os seus dados são passados para o servidor através de um POST.
HEAD
É similar ao GET, porém somente retorna os cabeçalhos da resposta, sem o corpo do documento requisitado. É útil para obter informações sobre o documento sem precisar baixá-lo.
PUT
Cria uma “cópia” do documento especificado no servidor. A principal diferença entre o POST e o PUT é que no primeiro, o recurso endereçado (URI) é o responsável pelo processamento dos dados sendo transmitidos na requisição, e no método PUT, a URI representa o documento que será criado ou modificado no servidor, contendo os dados especificados pelo cliente.
DELETE
Remove o documento especificado do servidor. O servidor retorna um código de status, informando se a solicitação foi aceita ou não.
TRACE
Retorna os cabeçalhos da requisição original, da mesma forma como foram recebidos pelo servidor. O TRACE é útil para o desenvolvedor analisar como a sua requisição está chegando do outro lado, pois diferentes cabeçalhos podem ser adicionados ou editados por servidores intermediários na rede. Pode-se utilizar o cabeçalho Max-Forwards para limitar o número de proxies ou servidores em que a mensagem deve trafegar antes de ser retornada para o cliente.
OPTIONS
Esse método permite que um cliente descubra quais as opções e/ou requisitos de um determinado recurso do servidor, sem a necessidade de se obter esse recurso (através do GET, por exemplo). Caso o recurso consultado seja “*”, as informações retornadas serão globais do servidor, e não de um documento específico. Dentre outras coisas, o OPTIONS informa quais os métodos HTTP suportados pelo servidor, visto que nem todos os servidores precisam implementar todos esses métodos (os servidores precisam disponibilizar sempre os métodos GET, HEAD e OPTIONS, sendo os restantes opcionais). Exemplo de uso do OPTIONS:
Requisição do cliente:
OPTIONS * HTTP/1.1 Host: proxy4.example.com Compliance: *
Servidor proxy4.example.com responde:
HTTP/1.1 200 OK Date: Tue, 22 Jul 1997 20:21:51 GMT Server: SuperProxy/1.0 Public: OPTIONS, GET, HEAD, PUT, POST, TRACE Compliance: rfc=1543, rfc=2068, hdr=set-proxy Compliance: hdr=wonder-bar-http-widget-set Content-Length: 0
CONNECT
Geralmente, o protocolo HTTP opera sobre a porta 80, e o protocolo seguro HTTPS sobre a porta 443. Para alguns, a necessidade de duas portas alocadas para essas funções é um desperdício. O HTTP/1.1 introduziu uma maneira de alterar entre modos de transmissão, mesmo sem utilizar a porta 443. Em um determinado momento, tanto o cliente quanto o servidor podem requisitar uma alteração do tipo de transmissão, passando para o protocolo seguro TLS, por exemplo. Essa troca de transmissão é requisitada através dos cabeçalhos Upgrade e Connection: Upgrade. A outra ponta pode aceitar ou não o pedido de mudança. Quando existe um proxy entre o cliente e o servidor final, é preciso criar um túnel que ligue as duas pontas diretamente, e é para isso que serve o método CONNECT: criar uma ponte entre cliente, proxies e o servidor, permitindo que a troca de mensagens ocorra diretamente, através do protocolo TLS.
Características dos métodos
Os métodos GET, HEAD, TRACE e OPTIONS são considerados “seguros”, ou seja, não afetam em nada o comportamento do servidor. Você pode executá-los quantas vezes quiser que o resultado retornado será sempre o mesmo (a menos que o servidor mude seu comportamento por conta própria), e essas requisições não causarão efeitos colaterais no servidor. Já os demais métodos, como PUT, POST e DELETE, afetam o estado do servidor quando executados. O PUT e o DELETE causam sempre a mesma mudança do servidor, podendo ser executados várias vezes que o resultado será sempre o mesmo. Mas o POST é diferente: requisições consecutivas desse método podem causar efeitos diferentes no servidor. Por exemplo, se você faz dois POSTs seguidos para a URL /blog/cadastra-comentario de um blog fictício, você pode estar cadastrando duas vezes os dados no servidor.
Como utilizar esses métodos
A maioria das aplicações na web faz uso somente dos métodos GET e POST, mas você pode utilizar alguns desses métodos do HTTP para tornar sua aplicação mais flexível e inteligente. Com PHP, por exemplo, é possível realizar qualquer tipo de chamada usando um socket, ou com a extensão cURL, que suporta HTTP e HTTPS.
Exemplo de HEAD usando socket:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 <?php
$fp = fsockopen('www.example.com', 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "HEAD /index.html HTTP/1.1\r\n";
$out .= "Host: www.example.com\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
A saída desse script é:
HTTP/1.1 200 OK Date: Wed, 27 Jan 2010 03:34:47 GMT Server: Apache/2.2.3 (CentOS) Last-Modified: Tue, 15 Nov 2005 13:24:10 GMT ETag: "b300b4-1b6-4059a80bfd280" Accept-Ranges: bytes Content-Length: 438 Connection: close Content-Type: text/html; charset=UTF-8
Note que deve existir uma linha em branco separando os cabeçalhos do corpo da mensagem. Neste caso, o corpo da mensagem de retorno está vazio, já que executamos um HEAD e não um GET.
E era isso!
No próximo post sobre HTTP, irei explorar os status codes do protocolo, ou seja, quais os códigos de retorno que um servidor pode responder para uma requisição.

