Você digita uma URL no browser, aperta Enter e, alguns segundos depois, uma página aparece na tela.
Para quem trabalha com frontend, é fácil pensar que uma aplicação começa quando o JavaScript começa a ser executado. Mas o browser começa a trabalhar muito antes disso.
Antes que o primeiro componente seja hidratado, que o primeiro fetch() da aplicação seja executado ou que o bundle principal comece a rodar, o browser já pode ter interpretado a URL, consultado mecanismos de cache, resolvido DNS, estabelecido uma conexão, negociado segurança, enviado uma requisição HTTP e começado a receber uma resposta.
Este post é a primeira parte de uma série sobre o caminho entre uma URL e os pixels exibidos na tela. Nesta parte, vamos acompanhar o processo até a resposta HTTP:
URL
→ cache / service worker
→ DNS
→ conexão
→ requisição HTTP
→ CDN / servidor
→ resposta HTTP
Esse é um modelo simplificado. HTTP/1.1 e HTTP/2 normalmente utilizam TCP e TLS, enquanto HTTP/3 usa QUIC sobre UDP e altera alguns detalhes do estabelecimento da conexão.
A ideia é entender esse processo a partir da própria Web Platform: URLs, origins, cache, service workers, DNS, conexões, TLS, HTTP, headers e DevTools. Frameworks rodam sobre essas fundações, e entendê-las torna muito mais fácil investigar problemas de performance, segurança e carregamento.
1. Interpretando a URL e determinando a origin
Imagine que você acesse:
https://example.com/products?id=123#reviews
O browser não trata isso como uma string qualquer. Ele interpreta a URL e a divide em componentes:
scheme/protocol: https
hostname: example.com
pathname/path: /products
query/search: ?id=123
fragment/hash: #reviews
O scheme, exposto como protocol pela API URL do JavaScript, define como o recurso deve ser acessado. Em uma página web comum, normalmente será HTTPS.
O hostname identifica o domínio ou endereço do host. O pathname identifica o caminho dentro daquela origin. A query string, exposta como search, carrega parâmetros adicionais, enquanto o fragment, exposto como hash, aponta para uma posição ou estado dentro do documento.
Um detalhe importante: o fragment normalmente não é enviado ao servidor como parte da requisição HTTP. Ele é tratado pelo browser no lado do cliente.
A partir da URL, o browser também consegue determinar sua origin. Uma origin é definida pela combinação de scheme, host e porta.
Por exemplo:
https://example.com
http://example.com
Essas URLs possuem origins diferentes porque os schemes são diferentes.
O mesmo acontece aqui:
https://example.com
https://api.example.com
Os schemes são iguais, mas os hosts são diferentes.
E aqui:
https://example.com
https://example.com:8443
O scheme e o host são os mesmos, mas as portas são diferentes. Portas padrão são normalizadas ao comparar origins, então https://example.com e https://example.com:443 são considerados a mesma origin.
Origin é um dos conceitos mais importantes da segurança no browser. Storage, service workers, permissões, CORS e a Same-Origin Policy dependem, de maneiras diferentes, dos limites entre origins.
Você pode inspecionar os componentes de uma URL diretamente no JavaScript:
const url = new URL("https://example.com/products?id=123#reviews");
console.log(url.protocol); // "https:"
console.log(url.hostname); // "example.com"
console.log(url.host); // "example.com"
console.log(url.pathname); // "/products"
console.log(url.search); // "?id=123"
console.log(url.hash); // "#reviews"
console.log(url.origin); // "https://example.com"
Também é útil entender a diferença entre host e hostname:
const url = new URL("https://example.com:8443/products");
console.log(url.host); // "example.com:8443"
console.log(url.hostname); // "example.com"
console.log(url.port); // "8443"
host inclui a porta quando ela está presente. hostname contém apenas o domínio ou endereço do host.
2. Antes da rede: cache e service workers
Depois de interpretar a URL, o browser precisa determinar como obter o recurso. Uma requisição de rede pode ser necessária, mas nem toda navegação ou carregamento começa do zero.
Browsers possuem diferentes camadas de cache e mecanismos relacionados, incluindo:
- HTTP cache;
- caches de memória e disco;
- back-forward cache, ou bfcache;
- Cache API;
- service workers.
Esses mecanismos não são necessariamente consultados em uma ordem fixa e universal. O comportamento depende do browser, do tipo de recurso, da navegação, do modo da requisição, dos headers de cache e do estado atual da página.
O HTTP cache é controlado principalmente pelas regras de cache do HTTP e por headers da resposta como Cache-Control, ETag e Last-Modified.
Cache-Control: max-age=3600
ETag: "abc123"
Last-Modified: Wed, 01 Jul 2026 12:00:00 GMT
O bfcache funciona de outra forma. Em vez de armazenar respostas individuais da rede, ele pode preservar uma página inteira em memória para que o browser a restaure rapidamente quando o usuário volta ou avança no histórico.
A Cache API é um armazenamento programável para pares de requisição e resposta. Ela é frequentemente utilizada em conjunto com service workers.
Um service worker não é simplesmente outro tipo de cache. Ele é um worker programável capaz de interceptar requisições dentro do seu escopo e decidir como respondê-las: usando a rede, a Cache API ou alguma outra estratégia.
Um service worker também não intercepta automaticamente a primeira visita a um site. Para controlar uma navegação, normalmente ele precisa já ter sido instalado, ativado e assumido o controle da página. Um primeiro acesso real geralmente ainda precisará da rede.
Um service worker simples usando uma estratégia cache first poderia ser:
const CACHE_NAME = "app-shell-v1";
const ASSETS = ["/", "/styles.css", "/main.js"];
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => cache.addAll(ASSETS)),
);
});
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request);
}),
);
});
Essa estratégia é chamada de cache first porque consulta o cache antes de recorrer à rede.
Cache pode tornar visitas seguintes muito mais rápidas, mas uma configuração incorreta também pode causar HTML desatualizado, assets antigos, deploys quebrados e comportamentos inconsistentes entre usuários. Por isso, entender de onde uma resposta veio é uma parte importante do debugging no frontend.
3. DNS: descobrindo onde se conectar
Se o browser precisar acessar a rede, ele terá que descobrir onde o servidor de destino pode ser encontrado.
Nós normalmente trabalhamos com nomes de domínio como example.com. A comunicação de rede, porém, precisa chegar a um endereço IP.
DNS, ou Domain Name System, é o sistema que relaciona nomes de domínio a informações como endereços IPv4 e IPv6.
Um fluxo simplificado de resolução pode ser representado assim:
cache do browser / sistema operacional
→ resolvedor DNS recursivo
→ root servers
→ TLD servers
→ authoritative nameserver
→ endereço IP
O browser normalmente não entra em contato diretamente com todos os servidores dessa hierarquia. Ele pode consultar caches locais e depois depender do sistema operacional ou de um resolvedor DNS configurado. O resolvedor recursivo pode já possuir a resposta em cache. Caso contrário, ele pode consultar a hierarquia do DNS em nome do cliente.
Os root servers ajudam a localizar os servidores responsáveis por um top-level domain, como .com ou .org. Os TLD servers então direcionam o resolvedor para o authoritative nameserver responsável pelo domínio solicitado.
Na prática, o uso de cache faz com que muitas consultas sejam resolvidas sem percorrer toda essa hierarquia.
Por que DNS importa para frontend engineers?
DNS adiciona trabalho antes que o browser consiga se conectar a um novo hostname. Se uma página depende de muitas origins externas, como serviços de analytics, fontes, hosts de imagens, APIs e widgets de terceiros, o browser pode precisar realizar resoluções DNS e conexões adicionais.
Cada origin externa pode introduzir custos relacionados a:
- resolução DNS;
- estabelecimento da conexão;
- negociação TLS;
- priorização de recursos;
- políticas de segurança;
- disponibilidade de serviços de terceiros.
Resource hints podem ajudar quando utilizados de forma intencional:
<link rel="dns-prefetch" href="https://fonts.gstatic.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
dns-prefetch sugere que a resolução DNS seja feita antecipadamente. preconnect vai além e pede ao browser que prepare uma conexão com aquela origin antes que ela seja necessária, podendo incluir a negociação TLS no caso de HTTPS.
Esses hints devem ser reservados para origins realmente importantes para o carregamento inicial. Preconnections em excesso podem desperdiçar recursos e competir com trabalhos mais críticos.
4. Estabelecendo a conexão
Depois que o browser sabe onde se conectar, ele precisa estabelecer uma conexão de transporte antes de trocar mensagens HTTP.
Para HTTP/1.1 e HTTP/2 sobre HTTPS, isso normalmente significa TCP seguido de TLS.
TCP
TCP, ou Transmission Control Protocol, oferece comunicação confiável e ordenada entre dois endpoints. Antes que os dados da aplicação possam ser trocados, cliente e servidor estabelecem uma conexão por meio do three-way handshake:
Client → SYN → Server
Client ← SYN/ACK ← Server
Client → ACK → Server
Os detalhes exatos do protocolo vão além do que a maioria dos frontend engineers precisa no dia a dia. O principal ponto relacionado à performance é entender que estabelecer uma nova conexão exige round trips pela rede.
Quanto mais distante o usuário estiver do servidor, maior será o custo desses round trips. Esse é um dos motivos pelos quais CDNs, edge servers, reutilização de conexões e versões mais modernas do HTTP podem melhorar a performance de carregamento.
TLS
Se a página utiliza HTTPS, cliente e servidor também estabelecem um canal seguro usando TLS, ou Transport Layer Security.
TLS oferece três propriedades que importam diretamente para a Web:
- autenticação — o browser consegue validar a identidade do servidor;
- confidencialidade — o tráfego é criptografado;
- integridade — alterações no tráfego durante o transporte podem ser detectadas.
Durante a negociação TLS, cliente e servidor concordam sobre parâmetros criptográficos, validam o certificado do servidor e estabelecem chaves para a comunicação protegida.
HTTPS não é uma troca opcional entre segurança e performance. Ele é um requisito fundamental de segurança para a Web moderna, e muitos recursos da Web Platform exigem um secure context.
O que muda com HTTP/3?
HTTP/3 não utiliza TCP. Ele roda sobre QUIC, que utiliza UDP e incorpora mecanismos de transporte confiável junto com TLS 1.3 ao processo de estabelecimento da conexão QUIC.
Portanto, este modelo mental:
DNS
→ TCP
→ TLS
→ HTTP
é útil para HTTP/1.1 e HTTP/2, mas não representa exatamente o funcionamento do HTTP/3.
5. Enviando a requisição HTTP
Quando a conexão está pronta, o browser pode solicitar o documento ao servidor.
Uma requisição simplificada de navegação em HTTP/1.1 poderia ser:
GET /products?id=123 HTTP/1.1
Host: example.com
Accept: text/html
Accept-Language: pt-BR
Accept-Encoding: gzip, br, zstd
O método GET indica que o cliente deseja obter uma representação de um recurso.
O request target /products?id=123 contém o pathname e a query string. Perceba que o fragment da URL original, como #reviews, não está incluído.
Os request headers fornecem contexto adicional. Accept descreve os tipos de mídia que o cliente consegue processar. Accept-Language informa preferências de idioma. Accept-Encoding lista os content encodings suportados. Cookies aplicáveis à requisição também podem ser enviados por meio do header Cookie.
HTTP/2 e HTTP/3 codificam as requisições de forma diferente do HTTP/1.1. Em vez da representação tradicional com uma request line, eles utilizam pseudo-headers como:
:method: GET
:scheme: https
:authority: example.com
:path: /products?id=123
A semântica continua familiar mesmo quando a representação na rede muda: o browser identifica o método, a origin de destino, o caminho e os metadados da requisição e envia essas informações ao servidor.
6. CDN, edge e origin
A requisição não necessariamente vai diretamente para o servidor que gerou a aplicação.
Muitos sites colocam uma CDN, ou Content Delivery Network, entre os usuários e o origin server.
Um caminho simplificado poderia ser:
Browser
→ CDN edge
→ origin server
Um edge server fica geograficamente mais próximo dos usuários do que o servidor de origem pode estar. Se ele já possui uma resposta válida em cache, consegue retorná-la sem consultar o origin server:
Browser
→ CDN edge
→ resposta em cache
Se a CDN não possui uma resposta válida em cache, ocorre um cache miss, e o edge pode buscar o recurso no servidor de origem:
Browser
→ CDN edge
→ origin server
→ CDN edge
→ Browser
Isso é especialmente útil para arquivos estáticos como CSS, JavaScript, imagens e fontes. HTML dinâmico também pode ser armazenado no edge quando a estratégia de cache da aplicação permite.
Essa parte do caminho está diretamente relacionada ao TTFB, ou Time to First Byte: o tempo entre o início da medição da navegação ou requisição e o momento em que o primeiro byte da resposta fica disponível para o browser.
Um TTFB alto pode ter várias causas, incluindo:
- latência de rede;
- DNS e estabelecimento da conexão;
- redirects;
- cache miss na CDN;
- servidores sobrecarregados;
- server-side rendering caro;
- queries lentas no banco de dados;
- chamadas a serviços externos.
TTFB é um sinal, não um diagnóstico. Ele mostra que o browser precisou esperar, mas não explica automaticamente o motivo.
7. Recebendo a resposta HTTP
Depois de processar a requisição, o servidor retorna uma resposta HTTP.
Uma resposta simplificada em HTTP/1.1 poderia ser:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: max-age=3600
Content-Encoding: br
Set-Cookie: session=abc; HttpOnly; Secure; SameSite=Lax
<!doctype html>
<html lang="pt-BR">
<head>
<title>Example</title>
</head>
<body>
<h1>Hello</h1>
</body>
</html>
Em alto nível, uma resposta HTTP contém três coisas:
- status — o que aconteceu;
- headers — metadados e instruções;
- body — o conteúdo propriamente dito.
Status codes comuns incluem 200 OK, redirects como 301 e 302, 304 Not Modified, erros do cliente como 404 Not Found e erros do servidor como 500 Internal Server Error.
Para frontend engineers, alguns response headers são especialmente importantes.
Content-Type
Content-Type informa ao browser que tipo de dado foi recebido, por exemplo text/html, text/css, application/json ou image/png.
Um content type incorreto pode fazer com que um recurso seja interpretado de forma errada ou até rejeitado completamente.
Cache-Control
Cache-Control define o comportamento de cache.
Um asset estático versionado pode utilizar uma política como:
Cache-Control: public, max-age=31536000, immutable
Isso funciona bem para nomes de arquivo que mudam sempre que o conteúdo muda, como /assets/main.8f3a2.js.
HTML normalmente exige uma estratégia mais cuidadosa, porque um documento desatualizado pode referenciar assets que já não existem depois de um deploy.
Validators como ETag e Last-Modified também permitem que o browser revalide conteúdo armazenado em cache e receba uma resposta 304 Not Modified quando o recurso não mudou.
Content-Encoding
Content-Encoding indica que o body da resposta foi codificado, normalmente com gzip, br (Brotli) ou zstd.
Compressão pode reduzir significativamente a quantidade de bytes transferidos em recursos baseados em texto.
Set-Cookie
Set-Cookie permite que o servidor armazene cookies no browser. Atributos como HttpOnly, Secure, SameSite, Path, Domain, Max-Age e Expires controlam o comportamento desses cookies.
Headers de segurança como Content-Security-Policy e headers relacionados a respostas cross-origin também são importantes. CORS, em particular, é aplicado pelo browser: quando as permissões cross-origin necessárias não estão presentes, o JavaScript pode ser impedido de ler uma resposta. Para requisições que exigem preflight, o browser pode primeiro enviar uma requisição OPTIONS e se recusar a enviar a requisição principal caso esse preflight falhe.
O body de uma navegação de documento normalmente é HTML. Quando o browser recebe esse HTML, começa a próxima etapa: interpretar o documento, descobrir recursos adicionais, construir as estruturas de renderização e, eventualmente, desenhar pixels na tela.
8. Observando o processo no DevTools
O lugar mais útil para observar esse caminho é o painel Network do DevTools do browser.
Faça este exercício:
- Abra uma janela privada ou anônima.
- Abra o DevTools.
- Vá até o painel Network.
- Ative Disable cache se quiser observar um carregamento de rede sem cache.
- Acesse um site.
- Selecione a requisição principal do documento.
- Analise Timing.
- Analise os request e response Headers.
Depois, tente responder:
- Houve algum redirect?
- A resposta veio de algum cache?
- Qual protocolo foi utilizado?
- Quanto tempo DNS e estabelecimento da conexão levaram?
- Qual foi o TTFB?
- Qual
Content-Typefoi retornado? - Qual política de
Cache-Controlfoi aplicada? - A resposta estava comprimida?
- Cookies foram enviados ou definidos?
- Headers de segurança estavam presentes?
Também é possível observar partes da navegação programaticamente por meio da Navigation Timing API:
const [navigation] = performance.getEntriesByType("navigation");
if (navigation) {
console.table({
dns: navigation.domainLookupEnd - navigation.domainLookupStart,
connection: navigation.connectEnd - navigation.connectStart,
tls:
navigation.secureConnectionStart > 0
? navigation.connectEnd - navigation.secureConnectionStart
: 0,
requestToFirstByte: navigation.responseStart - navigation.requestStart,
responseDownload: navigation.responseEnd - navigation.responseStart,
});
}
Alguns valores podem ser zero porque determinada etapa não foi necessária, uma conexão existente foi reutilizada ou o browser expõe a informação de maneira diferente. O objetivo não é decorar cada campo, mas relacionar o que o DevTools mostra com o processo de carregamento que acontece por baixo.
9. Por que frontend engineers deveriam se importar?
Todo esse caminho acontece antes que o browser consiga processar e renderizar completamente a aplicação.
Isso significa que muitos problemas que parecem ser de “performance do frontend” podem, na verdade, acontecer antes mesmo de o JavaScript se tornar relevante.
Uma página lenta pode ser causada por:
- um redirect desnecessário;
- resolução DNS lenta;
- origins externas em excesso;
- estabelecimento repetido de conexões;
- cache miss na CDN;
- alto tempo de processamento no servidor;
- regras de cache mal configuradas;
- uma resposta HTML grande e sem compressão.
O mesmo vale para segurança e debugging.
Um erro de CORS não é um erro do React. Uma violação de CSP não é um erro do bundler. Um deploy desatualizado pode ser um problema de cache. Um Content-Type incorreto pode fazer o browser rejeitar um arquivo perfeitamente válido. Um problema com cookies pode estar relacionado a SameSite, Secure, domínio ou path, e não ao estado da aplicação.
Frameworks podem gerar HTML, configurar headers, definir rotas, executar middleware, otimizar assets e integrar a aplicação com CDNs. Mas o browser continua trabalhando com URLs, origins, requisições HTTP, respostas HTTP, regras de cache e políticas de segurança.
Quando algo está lento ou quebrado, dizer apenas que “o framework está lento” raramente é um diagnóstico útil. Abra o painel Network e identifique onde o tempo está sendo gasto ou onde a falha realmente acontece.
Conclusão
Quando você digita uma URL no browser, uma quantidade surpreendente de trabalho acontece antes que a aplicação consiga renderizar qualquer coisa.
O browser interpreta a URL e determina sua origin. Caches existentes ou um service worker podem atender à requisição sem uma viagem completa pela rede. Caso contrário, o DNS resolve o hostname, o browser estabelece uma conexão, o HTTP transporta a requisição por uma infraestrutura que pode incluir uma CDN e o servidor retorna uma resposta contendo status, headers e body.
Um modelo mental útil é:
URL
→ mecanismos locais do browser
→ DNS
→ conexão
→ requisição HTTP
→ CDN / origin
→ resposta HTTP
Entender esse caminho facilita a investigação de performance de carregamento, bugs de cache, políticas de segurança, problemas de deploy e comportamentos inesperados do browser.
E essa é apenas a primeira metade da história.
Na próxima parte, o browser já terá recebido o HTML e precisará transformá-lo, junto com CSS e JavaScript, em algo que o usuário consiga ver:
HTML
→ DOM
→ CSSOM
→ render tree
→ layout
→ paint
→ composite
→ pixels na tela
Fontes recomendadas
- WHATWG URL Standard
- WHATWG Fetch Standard
- MDN: URL API
- MDN: Same-Origin Policy
- MDN: Service Worker API
- MDN: Cache API
- MDN: PerformanceNavigationTiming
- MDN: Cross-Origin Resource Sharing (CORS)
- MDN: Content Security Policy (CSP)
- RFC 1034 e RFC 1035: DNS
- RFC 8446: TLS 1.3
- RFC 9110: HTTP Semantics
- RFC 9111: HTTP Caching
- RFC 9112: HTTP/1.1
- RFC 9113: HTTP/2
- RFC 9114: HTTP/3
- RFC 9293: TCP
- Chrome DevTools Network panel documentation