Exploração

🖧 Como um servidor web processa uma request

Quando você acessa uma URL, o navegador abre uma conexão TCP e envia texto puro seguindo o protocolo HTTP. Do outro lado, o servidor aceita essa conexão, lê bytes, parseia a request, chama o código certo e devolve outra sequência de bytes. Veja cada etapa.

① Intuição

HTTP é texto. Um servidor web no fundo não passa de um programa que:

  1. Fica escutando em uma porta TCP (geralmente 80 ou 443)
  2. Aceita conexões de clientes
  3. Lê bytes, que são texto HTTP
  4. Decide o que fazer com base no path e método
  5. Devolve texto HTTP com o conteúdo

Frameworks como Flask, Express ou Rails são camadas de conveniência sobre esse loop fundamental.

② Visualização — ciclo de uma request

Avance pelos passos para ver a jornada de GET /artigos/42 desde o TCP accept até a resposta chegar de volta ao navegador.

🌐
Navegador
🔌
TCP/OS
🔍
Parser
🗺️
Router
⚙️
Handler
📄
Template
📨
Response
Passo 1/7: Cliente envia HTTP Request
O navegador abre uma conexão TCP e envia: GET /artigos/42 HTTP/1.1 com headers (Host, User-Agent, Accept…).
GET /artigos/42 HTTP/1.1 Host: exemplo.com Accept: text/html
1 / 7

③ Explicação técnica

Socket TCP — escutar e aceitar

import socket

# Criar socket TCP
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('0.0.0.0', 8080))
server.listen(128)        # backlog: fila de conexões pendentes

while True:
    conn, addr = server.accept()   # bloqueia até nova conexão
    data = conn.recv(4096)         # lê a HTTP request
    handle_request(conn, data)
    conn.close()

Parse da HTTP request

HTTP/1.1 usa texto delimitado por \r\n. O parse é uma leitura de string:

def parse_request(raw: bytes) -> dict:
    text = raw.decode('utf-8')
    lines = text.split('\r\n')

    # Primeira linha: "GET /artigos/42 HTTP/1.1"
    method, path, version = lines[0].split(' ')

    # Headers até linha em branco
    headers = {}
    for line in lines[1:]:
        if not line:
            break
        key, _, value = line.partition(': ')
        headers[key.lower()] = value

    return {'method': method, 'path': path, 'headers': headers}

Roteamento

O router compara o path contra padrões e delega ao handler correto:

import re

ROUTES = [
    ('GET',  r'^/$',              handler_home),
    ('GET',  r'^/artigos$',       handler_lista),
    ('GET',  r'^/artigos/(\d+)$', handler_artigo),
    ('POST', r'^/artigos$',       handler_criar),
]

def route(method, path):
    for m, pattern, handler in ROUTES:
        if m == method:
            match = re.match(pattern, path)
            if match:
                return handler, match.groups()
    return handler_404, ()

Montar e enviar a response

def send_response(conn, status, body, content_type='text/html'):
    body_bytes = body.encode('utf-8')
    response = (
        f"HTTP/1.1 {status}\r\n"
        f"Content-Type: {content_type}; charset=utf-8\r\n"
        f"Content-Length: {len(body_bytes)}\r\n"
        f"Connection: close\r\n"
        f"\r\n"
    ).encode() + body_bytes
    conn.sendall(response)

Códigos de status importantes

CódigoSignificadoQuando usar
200 OKSucessoResposta normal
201 CreatedCriadoApós POST bem-sucedido
301/302RedirectMudança de URL
400Bad RequestRequest malformada
404Not FoundRecurso não existe
500Server ErrorErro no código do servidor

④ Projeto

Escreva um servidor HTTP do zero (sem frameworks, só stdlib):

  1. Crie um socket TCP que escuta na porta 8080
  2. Aceite conexões em loop
  3. Leia e parseia a request (método + path + headers)
  4. Implemente 3 rotas: GET /, GET /about, GET /json
  5. Responda com HTML ou JSON adequado
  6. Bônus: suporte a múltiplas conexões simultâneas com threading

⑤ Perguntas rápidas

⑥ Aplicações no mundo real