Categorias
Firefox www

O que realmente acontece quando você acessa uma URL

Acontece bastante coisa quando você acessa um site e de tanto fazer isso a gente se esquece de como funciona e deixa de valorizar a enorme infraestrutura que mantém tudo isso funcionando. Eu li um artigo esses dias e resolvi adaptar para uma versão brasileira, boa leitura!

Como um desenvolvedor de software, certamente você tem uma ideia bem por cima de como funcionam as aplicações web e quais os tipos de tecnologias estão envolvidos: o navegador, HTTP, HTML, o servidor web, gerenciamento de requests e assim por diante.

Neste artigo, vamos dar uma olhada mais a fundo na sequência de eventos que acontecem quando você visita um URL.

1. Você digita o endereço do site (URL) no navegador web:

Tudo começa aqui:



2. O navegador procura o endereço IP para o nome do domínio

O primeiro passo para a navegação é descobrir o endereço IP do domínio visitado.

O lookup do DNS acontece da seguinte forma:

    • Cache do navegador – o navegador faz cache dos registros do DNS por algum tempo. Curiosamente o sistema operacional não fala ao navegador o tempo de vida de cada registro do DNS, e portanto o navegador guarda por um tempo fixo que varia entre 2 e 30 minutos dependendo do navegador.
    • Cache do sistema operacional – se o cache do browser não contém o registro desejado, o navegador faz uma chamada de sistema (gethostbyname no Windows e Linux). O sistema operacional tem seu próprio cache.
    • Cache do roteador – a requisição continua no seu roteador, que normalmente tem seu cache de DNS próprio.
    • ISP DNS cache – The next place checked is the cache ISP’s DNS server.
    • Cache DNS do seu provedor – O próximo lugar é o servidor verificar o cache de DNS do seu provedor (Internet Service Provider), que naturalmente também possui um cache.

Busca recursiva – Seu servidor de DNS do seu provedor começa uma busca recursiva, a partir do servidor de nomes raiz, através do nível maior .com e descendo para o servidor de nomes do Facebook. Normalmente, o servidor DNS tem os nomes dos servidores .com em cache, e assim que um acesso ao servidor de nomes raiz não será necessário.

Aqui está um diagrama do que uma pesquisa DNS recursivo parece:

Uma coisa preocupante sobre o DNS é que todo o domínio wikipedia.org ou facebook.com mapeia para um único endereço IP, mas felizmente, existem maneiras de diminuir esse gargalo:

    • Round-robin DNS é uma solução onde o DNS retorna vários endereços IP, em vez de apenas um. Por exemplo, o facebook.com realmente mapeia para quatro endereços IP.
    • Load-balancer (balanceamento de carga) é um hardware que escuta um específico endereço IP e encaminha a requisição para outros servidores. A maioria dos grandes sites usa um balanceamento de carga de alta performance que costuma custar caro.
    • Geographic DNS melhora a escalabilidade, mapeando um nome de domínio para diferentes endereços IP , dependendo da localização geográfica do cliente.
      Isso é ótimo para a hospedagem de conteúdo estático para que servidores diferentes não tenham que atualizar o estado compartilhado toda hora.
    • Anycast é uma técnica de roteamento em que um único endereço IP mapeia múltiplos servidores físicos. Infelizmente o anycast não se encaixa bem com TCP e raramente é usado nesse cenário.

A maioria dos servidores de DNS próprios usam anycast para alcançar alta disponibilidade e baixa latência do DNS.

3. O navegador envia uma requisição HTTP para o servidor web

Você pode ter certeza que a página do Facebook não virá do cache do browser, porque as páginas dinâmicas expiraram muito rápido ou imediatamente (a data de validade vem fixa para o passado).

Assim, o browser vai enviar esta requisição para o servidor Facebook:

GET / HTTP/1.1
Host: facebook.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20110407 Firefox/4.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: pt-br,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Cookie: datr=1261098066-a8f926188683ac0ea09fcd9f28bba06e82e2304fa1d5ced3f9ffa; lsd=5J8NE; reg_fb_gate=http%3A%2F%2Fwww.facebook.com%2F; reg_fb_ref=http%3A%2F%2Fwww.facebook.com%2F; wd=1050×756

A requisição GET chama a URL para buscar: “http://facebook.com/”. O navegador se identifica (User-Agent no cabeçalho), e afirma que tipos de respostas vai aceitar (Accept e Accept-Encoding no cabeçalho). O Connection do cabeçalho pede ao servidor para manter a conexão TCP aberta para outros pedidos.

O pedido inclui também os cookies que o navegador tem para este domínio. Como você provavelmente já sabe, os cookies são valores chave do tipo chave=valor , que completam o estado de um site, entre diferentes requisições de páginas. E assim, os cookies armazenam o nome do usuário logado, um número secreto que foi atribuído ao usuário pelo servidor, algumas das configurações do usuário, etc. Os cookies serão guardados em um arquivo de texto no caso do Internet Explorer e em um banco de dados no caso do Firefox, e enviados para o servidor a cada requisição.

Existe uma grande variedade de ferramentas que permitem visualizar as requisições HTTP e suas respostas correspondentes.
Minha ferramenta favorita para a visualização do tráfego HTTP no IE é o fiddler, e no Firefox temos o Firebug e também o Live HTTP Headers .

Além das requisições GET, outro tipo de requisições que você pode estar familiarizado com uma requisição POST, tipicamente usado para enviar formulários.

A requisição GET envia os seus parâmetros através do URL (ex.: http://robozzle.com/puzzle.aspx? Id = 85) e a requisição POST envia os parâmetros no corpo da requisição, logo abaixo do cabeçalho.

A barra final da URL “http://facebook.com/” é importante. Neste caso, o navegador pode seguramente adicionar a barra. Para URLs com um formulário http://exemplo.com/pastaOuArquivo o navegador não pode adicionar automaticamente uma barra, porque não está claro se pastaOuArquivo é uma pasta ou um arquivo. Nesses casos, o navegador vai visitar a URL sem a barra, e o servidor responderá com um redirecionamento, resultando em uma ida desnecessária.

4. O servidor responde com um redirecionamento permanente ao Facebook

Esta é a resposta que o servidor Facebook enviou de volta para a requisição do navegador:

HTTP/1.1 301 Moved Permanently
Location: http://www.facebook.com/
Content-Type: text/html; charset=utf-8
X-FB-Server: 10.27.51.117
X-Cnection: close
Date: Sun, 01 May 2011 04:05:36 GMT
Content-Length: 0

O servidor respondeu com uma resposta de “301 Movido Permanentemente” para dizer ao navegador para ir para “http://www.facebook.com/” em vez de “http://facebook.com/”.

Há razões interessante porque o servidor insiste no redirecionamento em vez de responder imediatamente com a página web que o usuário quer ver.
Uma das razões tem a ver com o motor de pesquisa de posições (rankings).

Veja, se existirem duas URLs para a mesma página, digamos http://www.igoro.com/ e http://igoro.com/, motor de busca pode considerar dois sites diferentes, cada uma com menos links recebidos e assim, uma classificação mais baixa.
Os motores de busca compreendem o redirecionamento permanente (301), e combinam os links recebidos de ambas as fontes em um ranking único.

Além disso, várias URLs para o mesmo conteúdo não ficam facilmente em cache (cache-friendly) . Quando uma parte do conteúdo tem vários nomes, ela pode aparecer várias vezes no mesmo cache.

5. O browser segue o redirecionamento

O navegador agora sabe que “http://www.facebook.com/” é o URL correto para ir, e assim ele envia um pedido GET:

http://www.facebook.com/

GET / HTTP/1.1
Host: www.facebook.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20110407 Firefox/4.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: pt-br,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Cookie: datr=1261098066-a8f926188683ac0ea09fcd9f28bba06e82e2304fa1d5ced3f9ffa; lsd=5J8NE; reg_fb_gate=http%3A%2F%2Fwww.facebook.com%2F; reg_fb_ref=http%3A%2F%2Fwww.facebook.com%2F; wd=1050×756

O significado dos cabeçalhos é o mesmo que para a primeira requisição.

6.O servidor trata a requisição

O servidor receberá o pedido GET, processará e enviará uma resposta.

Isto pode parecer uma tarefa simples, mas na verdade há um monte de coisas interessantes que acontecem aqui – mesmo em um site simples como o meu blog, não só em um site altamente escalável como o Facebook.

* Software do servidor Web

O software de servidor web (por exemplo, o IIS ou Apache) recebe a requisição HTTP e decide qual gerenciador de requisição (request handler) deve ser executado para processar este pedido.

Um manipulador de requisição é um programa (em ASP.NET, PHP, Ruby, …) que lê a requisição e gera o código HTML para a resposta.

No caso mais simples, os gerenciadores de requisição podem ser armazenados em uma hierarquia de arquivo cuja estrutura reflete a estrutura de URL, e assim por exemplo http://example.com/pasta1/pagina1.aspx URL irá mapear para o arquivo /httpdocs/pasta1/pagina1.aspx ou C:\site\pasta1\pagina1.aspx .

O software de servidor web também pode ser configurado para que as URLs sejam mapeadas para os gerenciadores de requisição, e assim a URL público da pagina1.aspx poderia ser http://example.com/pasta1/pagina1.

* Request handler

O gerenciador lê a requisição, seus parâmetros e os seus cookies. Ele vai ler e, eventualmente, atualizar alguns dados armazenados no servidor. Em seguida, o gerenciador de requisição gerará uma resposta HTML.

Uma dificuldade interessante que cada site dinâmico enfrenta é a forma de armazenamento de dados. Os sites menores, muitas vezes, ter um único banco de dados SQL para armazenar seus dados, mas sites que armazenam uma grande quantidade de dados e / ou tem muitos visitantes têm de encontrar uma maneira de dividir o banco de dados através de múltiplas máquinas.As soluções incluem sharding (divisão de uma tabela em vários bancos de dados com base na chave primária), replicação e uso de bases de dados simplificada com consistência semântica enfraquecida.

Uma técnica para manter a atualização dos dados mais leve é adiar alguns dos trabalhos para um trabalho em lote. Por exemplo, o Facebook tem que atualizar o newsfeed em tempo hábil, mas os dados de apoio do recurso “pessoas que você pode conhecer” pode apenas ser atualizado de noite . O trabalho em lote resulta em um pouco de lentidão geral nas atualizações com dados menos importantes, mas pode fazer atualizações de dados muito mais rápido e mais simples.

7. O servidor envia de volta uma resposta HTML

Aqui está a resposta que o servidor gerado e enviado de volta:

HTTP/1.1 200 OK
Cache-Control: private, no-cache, no-store, must-revalidate
Expires: Sat, 01 Jan 2000 00:00:00 GMT
P3P: CP=”Facebook does not have a P3P policy. Learn why here: http://fb.me/p3p”
Pragma: no-cache
Set-Cookie: reg_fb_ref=http%3A%2F%2Fwww.facebook.com%2F; path=/; domain=.facebook.com
Set-Cookie: wd=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.facebook.com; httponly
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
X-FB-Server: 10.144.145.118
X-Cnection: close
Transfer-Encoding: chunked
Date: Sun, 01 May 2011 04:05:37 GMT

O cabeçalho Content-Encoding informa ao navegador que a resposta do corpo é comprimido utilizando o algoritmo gzip.
Depois de descomprimir o blob, você verá o código HTML que você esperaria:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt" lang="pt" id="facebook" class=" no_js">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-language" content="pt" />
<script type="text/javascript">
//<![CDATA[
CavalryLogger=false;window._script_path = "\/index.php";window._EagleEyeSeed="wP2A";__rm = {};
//]]>
</script><noscript> <meta http-equiv=refresh content="0; URL=/?_fb_noscript=1" /> </noscript>

<meta name="robots" content="noodp,noydir" />
<meta name="description" content=" O Facebook é uma rede social que reúne pessoas a seus amigos e àqueles com quem trabalham, estudam e convivem. As pessoas participam do Facebook para manter contato com seus amigos, carregar um número ilimitado de fotos, compartilhar links e vídeos e aprender mais sobre as pessoas que conhecem.<br /><br />" />
<link rel="alternate" media="handheld" href="http://www.facebook.com/" />
<title>Bem-vindo ao Facebook - acesse, cadastre-se ou saiba mais.</title><noscript><meta http-equiv="X-Frame-Options" content="deny" /></noscript>
<link type="text/css" rel="stylesheet" href="http://b.static.ak.fbcdn.net/rsrc.php/v1/yZ/r/dBoSKLwxlh0.css" />
<link type="text/css" rel="stylesheet" href="http://static.ak.fbcdn.net/rsrc.php/v1/y1/r/CkuMXVTz1uq.css" />
<link type="text/css" rel="stylesheet" href="http://b.static.ak.fbcdn.net/rsrc.php/v1/y8/r/--vMHqIJi-S.css" />

 

Além de compressão, os cabeçalhos especificam se e como fazer o cache da página, e se existem cookies para definir (nenhum nesta resposta), informações particulares, etc.

Observe que o cabeçalho define o Content-Type como text/html. O cabeçalho instrui o navegador para renderizar o conteúdo da resposta como HTML, em vez de dizer como fazer o download de um arquivo. O navegador usará o cabeçalho para decidir como interpretar a resposta, mas no caso do IE pode considerar também a extensão da URL.

8. O navegador começa a renderização da página HTML

Antes mesmo do navegador receber todo o documento HTML, ela começa a tornar o renderizar o site:

9. O navegador envia requisições para os objetos dentro do HTML

Como o navegador processa o HTML, ele vai notar as tags que exigem busca de outras URLs.

O browser enviará uma requisição GET para recuperar cada um desses arquivos.

Aqui estão algumas URLs que a minha visita a facebook.com baixou:

* Imagens
http://static.ak.fbcdn.net/rsrc.php/v1/yp/r/kk8dc2UJYJ4.png
… …
* Folhas de estilo (CSS)
http://b.static.ak.fbcdn.net/rsrc.php/v1/yZ/r/dBoSKLwxlh0.css
http://static.ak.fbcdn.net/rsrc.php/v1/y1/r/CkuMXVTz1uq.css
… …
* Arquivos JavaScript
http://static.ak.fbcdn.net/rsrc.php/v1/yg/r/vnWtCAcBiXn.js
… …

Cada um desses URLs vai passar por um processo semelhante ao que a página HTML passou.
Assim, o browser irá procurar o nome de domínio no DNS, enviar uma requisição para o URL, siga redirecionamentos, etc.

No entanto, arquivos estáticos – ao contrário de páginas dinâmicas – permitem que o navegador faça o cache deles.

Alguns dos arquivos podem ser acessados a partir do cache, sem contato com o servidor.
O navegador sabe quanto tempo demora para colocar um arquivo em cache, porque a resposta que retornou o arquivo continha um cabeçalho expirado.
Além disso, cada resposta pode também conter um cabeçalho ETag que funciona como um número de versão – se o navegador vê um ETag para uma versão do arquivo que já possui, ele pode parar a transferência imediatamente.

Você consegue adivinhar o que fbcdn.net na URLs significa? Um bom palpite seria que ela significa “Facebook content delivery network (rede de distribuição de conteúdo do Facebook)”. O Facebook usa uma rede de distribuição de conteúdo (CDN) para distribuir o conteúdo estático – imagens, folhas de estilo, e os arquivos JavaScript. Assim, os arquivos serão copiados para muitas máquinas ao redor do mundo.

O conteúdo estático, muitas vezes representa a maior parte da largura de banda de um site, e pode ser facilmente replicado em um CDN. Muitas vezes, os sites usam um fornecedor de conteúdo terceirizado ao invés deles cuidarem disso. Por exemplo, arquivos estáticos do Facebook são hospedados por Akamai, o maior fornecedor de CDN.

Como teste, quando você tenta fazer ping static.ak.fbcdn.net, você receberá uma resposta de um servidor akamai.net.
Além disso, curiosamente, se você executar ping o URL de um par de vezes, pode obter respostas de servidores diferentes, o que demonstra o balanceamento de carga, que acontece nos bastidores.

10. O navegador envia mais requisições assíncronas (AJAX)

No espírito da Web 2.0, o cliente continua a comunicar com o servidor, mesmo após a página ser processada.

Por exemplo, o chat do Facebook continuará a atualizar a lista de seus amigos registrados logo que eles entram e saem.
Para atualizar a lista de seus amigos registrados, a execução de JavaScript no seu navegador tem que enviar uma requisição assíncrona para o servidor.
O pedido assíncrono é uma programação construída GET ou requisição POST que vai para um endereço especial.
No exemplo do Facebook, o cliente envia uma requisição POST para http://www.facebook.com/ajax/chat/buddy_list.php para buscar a lista de seus amigos que estão online.

Este padrão é muitas vezes referida como “AJAX”, que significa “Asynchronous Javascript And XML”, ainda que não exista nenhuma razão específica para que o servidor tenha que formatar a resposta como XML.

Por exemplo, as rotinas do Facebook retornam de código JavaScript em resposta às requisições assíncronas.

Entre outras coisas, a ferramenta Fiddler permite visualizar os pedidos assíncronos enviados pelo seu navegador.
Na verdade, não só você pode observar os pedidos de forma passiva, mas você também pode modificar e reenviá-los.
O fato de que é tão fácil de “espiar” pedidos AJAX causa muita tristeza para os desenvolvedores de jogos on-line com painéis de avaliação.

O chat do Facebook fornece um exemplo de um problema interessante com AJAX: empurrando dados do servidor para o cliente. Uma vez que o HTTP é um protocolo de pedido-resposta, o servidor de chat não pode empurrar as novas mensagens para o cliente. Em vez disso, o cliente tem de consultar o servidor a cada poucos segundos para ver se alguma nova mensagem chegou.

O Long polling é uma técnica interessante para diminuir a carga no servidor nesses tipos de cenários. Se o servidor não tem nenhuma mensagem nova, quando em polling, ele simplesmente não envia uma resposta de volta. E, se uma mensagem para este cliente é recebida dentro do tempo limite, o servidor encontra-se a requisição pendente e retornar a mensagem com a resposta.

Conclusão

Esperemos que esse artigo esclareça um pouco mais de como as diferentes partes web trabalham juntas.

Fernando Boaglio, para a comunidade. =)