HTTP do zero: request, response, status, headers, cookies
HTTP (HyperText Transfer Protocol) é o protocolo que move a web inteira. APIs REST, webhooks, browsers, apps mobile — tudo fala HTTP. Entender sua estrutura real não é opcional para quem desenvolve software moderno.
Anatomia de uma request e response HTTP
# Request HTTP/1.1 completa (o que vai pelo fio):
GET /api/users/42 HTTP/1.1
Host: api.exemplo.com
Accept: application/json
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...
User-Agent: curl/8.4.0
Connection: keep-alive
# Request POST com body:
POST /api/users HTTP/1.1
Host: api.exemplo.com
Content-Type: application/json
Content-Length: 52
Authorization: Bearer eyJhbGci...
{"name": "Fernando", "email": "f@exemplo.com"}
# Response HTTP/1.1 completa:
HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 89
Location: /api/users/43
X-Request-Id: abc-123-def
Cache-Control: no-store
Date: Thu, 17 Apr 2026 10:00:00 GMT
{"id": 43, "name": "Fernando", "email": "f@exemplo.com", "created_at": "..."} Toda request tem: método + path + versão na primeira linha, headers (um por linha, formato Nome: Valor), linha em branco, e opcionalmente um body. Response tem: versão + status code + reason phrase, headers, linha em branco, e o body da resposta.
Métodos HTTP: semântica importa
| Método | Semântica | Idempotente? | Tem body? |
|---|---|---|---|
| GET | Leitura — nunca modifica | Sim | Não (prática) |
| POST | Criação / ação não-idempotente | Não | Sim |
| PUT | Substituição completa do recurso | Sim | Sim |
| PATCH | Atualização parcial | Não necessariamente | Sim |
| DELETE | Remoção do recurso | Sim | Não (prática) |
| HEAD | Igual GET, mas sem body na response | Sim | Não |
| OPTIONS | Quais métodos são suportados? (CORS preflight) | Sim | Não |
# Idempotência na prática:
# PUT /users/42 com body completo → mesmo resultado toda vez = idempotente
# DELETE /users/42 → mesmo resultado (404 na 2ª vez, mas o estado final é igual)
# POST /orders → cria um novo pedido a cada chamada = NÃO idempotente
# Idempotency key para POST seguro (padrão stripe/paypal):
POST /api/payments
Idempotency-Key: client-generated-uuid-abc123
{"amount": 100, "currency": "BRL"}
# Servidor: se já processou esta key, retorna o resultado original sem processar novamenteStatus codes: o que cada faixa significa
| Faixa | Categoria | Exemplos importantes |
|---|---|---|
| 1xx | Informacional | 101 Switching Protocols (WebSocket upgrade) |
| 2xx | Sucesso | 200 OK, 201 Created, 204 No Content |
| 3xx | Redirecionamento | 301 Moved Permanently, 302 Found, 304 Not Modified |
| 4xx | Erro do cliente | 400 Bad Request, 401 Unauth, 403 Forbidden, 404 Not Found, 429 Too Many Requests |
| 5xx | Erro do servidor | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable |
# Status codes que todo dev confunde:
# 200 vs 201 vs 204:
GET /users/42 → 200 OK + body
POST /users → 201 Created + body + header Location: /users/43
DELETE /users/42 → 204 No Content (sem body)
# 301 vs 302 vs 307 vs 308:
# 301 Moved Permanently → browser e crawlers atualizam a URL (SEO redirect)
# 302 Found → redirect temporário (crawlers não atualizam)
# 307 Temporary Redirect → como 302, mas garante manter o método HTTP
# 308 Permanent Redirect → como 301, mas garante manter o método HTTP
# 400 vs 422:
# 400 Bad Request → request malformada (JSON inválido, campos obrigatórios faltando)
# 422 Unprocessable Entity → sintaxe OK, mas semanticamente inválido
# (email formatado corretamente mas já cadastrado)
# 401 vs 403:
# 401 → não autenticado → mostre tela de login
# 403 → autenticado mas sem permissão → mostre "acesso negado"
# 429 Too Many Requests → rate limited
# Boas APIs incluem: Retry-After: 60 (segundos para aguardar)Headers: metadados que controlam tudo
# Headers de Autenticação
Authorization: Bearer <JWT-token>
Authorization: Basic <base64(user:pass)>
X-API-Key: abc123 # padrão de APIs simples
# Headers de Conteúdo
Content-Type: application/json # formato do BODY enviado
Content-Type: multipart/form-data # upload de arquivo
Accept: application/json # formato que o cliente ACEITA na resposta
Content-Length: 1234 # tamanho em bytes do body
Content-Encoding: gzip # body está comprimido
# Headers de Cache
Cache-Control: no-cache # sempre revalida com o servidor
Cache-Control: no-store # não cacheia (dados sensíveis)
Cache-Control: max-age=3600 # cacheia por 1 hora
Cache-Control: public, max-age=86400 # cacheia em CDN por 1 dia
ETag: "abc123" # identifier da versão do recurso
If-None-Match: "abc123" # request condicional → 304 se não mudou
# Headers de Rate Limiting (de facto padrão)
X-RateLimit-Limit: 1000 # total de requests permitidas
X-RateLimit-Remaining: 999 # quanto sobra na janela atual
X-RateLimit-Reset: 1713350400 # quando a janela reseta (Unix timestamp)
Retry-After: 60 # segundos para aguardar (em 429)
# Headers de Segurança (response)
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Security-Policy: default-src 'self'CORS: por que o browser bloqueia, mas curl não
# CORS: Cross-Origin Resource Sharing
# Origin = protocolo + host + porta: https://app.com vs https://api.com = origens diferentes
# 1. PREFLIGHT (request OPTIONS automática do browser antes de POST/PUT/custom headers):
OPTIONS /api/users HTTP/1.1
Origin: https://app.meusite.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization, Content-Type
# 2. Server responde ao preflight:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.meusite.com # ou: * para qualquer origem
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400 # cacheia o preflight por 1 dia
# 3. Browser envia a request real
# Se Access-Control-Allow-Origin não incluir a origem → browser bloqueia
# Configuração em Express.js:
app.use(cors({
origin: ['https://app.meusite.com', 'https://admin.meusite.com'],
credentials: true, // necessário para enviar cookies cross-origin
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
}));
# CORS com credentials (cookies/auth headers cross-origin):
# Server: Access-Control-Allow-Credentials: true + Access-Control-Allow-Origin NÃO pode ser *
# Client: fetch(url, { credentials: 'include' })Ferramentas para explorar HTTP: curl -v (veja headers completos), httpie (syntax mais amigável), Postman/Insomnia (GUI), DevTools → Network (browser) → clique na request → Headers.
Próximo: DNS, TLS e certificados — o que acontece nos milissegundos antes do seu request HTTP chegar ao servidor.
Próximos passos sugeridos
Discussão
Carregando…