0%
Python no Servidor: do CGI às Aplicações WSGI Modernas

Python no Servidor: do CGI às Aplicações WSGI Modernas

Explore a evolução do desenvolvimento web em Python: CGI, suas limitações, WSGI e a transição para Flask/FastAPI para aplicações modernas e de alto desempenho.

I

InSkillCoach

· min

Python no Servidor: do CGI às Aplicações WSGI Modernas

A Common Gateway Interface (CGI) foi a primeira forma de gerar conteúdo dinâmico na web, nos anos 1990. Embora revolucionária na época, a CGI sofre de uma limitação importante: cada requisição inicia um novo processo Python, o que é ineficiente e inviável em escala. A WSGI (Web Server Gateway Interface) introduziu um modelo mais eficiente em 2003. Hoje, frameworks WSGI como Flask e servidores ASGI como FastAPI dominam o cenário. Este guia traça essa evolução e mostra como migrar da CGI para as tecnologias modernas.

1. CGI: As Origens

O que é CGI?

CGI é um padrão que define como um servidor web (Apache, Nginx) executa um programa externo (script CGI) para processar uma requisição HTTP e gerar uma resposta.

O fluxo CGI:

  1. O cliente envia uma requisição HTTP ao servidor web
  2. O servidor web inicia um novo processo para executar o script CGI
  3. O script lê a entrada (variáveis de ambiente, stdin)
  4. O script gera uma saída (headers HTTP + body)
  5. O servidor web devolve a resposta ao cliente
  6. O processo termina

Exemplo mínimo de CGI

Suponha um servidor web configurado para executar os scripts .cgi em /cgi-bin/.

#!/usr/bin/env python
# Arquivo : /cgi-bin/hello.cgi

import cgi
import cgitb

# Ativar os relatórios de erro CGI
cgitb.enable()

print("Content-Type: text/html; charset=utf-8")
print()

print("<html><body>")
print("<h1>Bonjour depuis CGI !</h1>")
print("</body></html>")

# Resultado : o servidor web envia uma resposta HTML ao navegador

Formulário CGI com processamento

#!/usr/bin/env python
# Arquivo : /cgi-bin/form_handler.cgi

import cgi
import html

# Fazer o parsing dos dados do formulário
form = cgi.FieldStorage()
nom = form.getvalue("nom", "Visiteur inconnu")

# Escapar o conteúdo para evitar injeções XSS
nom_safe = html.escape(nom)

print("Content-Type: text/html; charset=utf-8")
print()

print("<html><body>")
print(f"<h1>Bienvenue, {nom_safe} !</h1>")
print("</body></html>")

# Requisição : GET /form_handler.cgi?nom=Alice
# Resposta : <h1>Bienvenue, Alice !</h1>

Limitações da CGI

LimitaçãoImpacto
Novo processo por requisiçãoCusto de inicialização enorme; inviável em escala
Módulo cgi descontinuado e depois removidoDepreciado desde o Python 3.11, com aviso; totalmente removido no Python 3.13
Sem estado persistenteAs conexões com o banco de dados são reabertas a cada requisição
Sem otimizaçõesSem cache, sem pool de workers, sem concorrência
Segurança por conta do desenvolvedorSem proteção integrada contra injeções, CSRF, etc.

2. WSGI: Um Modelo Melhor

O que é WSGI?

A WSGI (PEP 3333) é uma interface padronizada entre um servidor web e uma aplicação Python. Diferentemente da CGI, a aplicação permanece em memória entre as requisições, o que elimina o custo de inicialização.

Uma aplicação WSGI é uma função ou classe callable que aceita dois argumentos:

def application(environ, start_response):
    """
    environ : dicionário contendo as informações da requisição HTTP
    start_response : função para enviar os headers de resposta
    
    Retorno : iterável de bytes (o body da resposta)
    """
    status = "200 OK"
    response_headers = [("Content-Type", "text/html; charset=utf-8")]
    start_response(status, response_headers)
    
    body = "<html><body><h1>Bonjour WSGI !</h1></body></html>"
    return [body.encode("utf-8")]

# Resultado : aplicação mais eficiente que a CGI

Exemplo de WSGI com formulário

from urllib.parse import parse_qs
import html

def app(environ, start_response):
    """Aplicação WSGI simples com processamento de formulário."""
    
    method = environ["REQUEST_METHOD"]
    path = environ.get("PATH_INFO", "/")
    
    if method == "GET" and path == "/":
        # Página inicial com formulário
        body = """
        <html>
        <body>
            <h1>Entrez votre nom</h1>
            <form method="post" action="/submit">
                <input type="text" name="nom" required>
                <button type="submit">Envoyer</button>
            </form>
        </body>
        </html>
        """.encode("utf-8")
        
        start_response("200 OK", [("Content-Type", "text/html; charset=utf-8")])
        return [body]
    
    elif method == "POST" and path == "/submit":
        # Processar os dados do formulário
        content_length = int(environ.get("CONTENT_LENGTH", 0))
        body = environ["wsgi.input"].read(content_length).decode("utf-8")
        data = parse_qs(body)
        nom = data.get("nom", ["Visiteur"])[0]
        nom_safe = html.escape(nom)
        
        response = f"<html><body><h1>Bonjour, {nom_safe} !</h1></body></html>".encode("utf-8")
        
        start_response("200 OK", [("Content-Type", "text/html; charset=utf-8")])
        return [response]
    
    else:
        start_response("404 Not Found", [("Content-Type", "text/plain")])
        return [b"Page non trouvée"]

# Executar com wsgiref (servidor de desenvolvimento incluído)
# python -m wsgiref.simple_server --port 8000 app:app
# Acesse http://localhost:8000

Servir uma aplicação WSGI pura com wsgiref

# Arquivo : myapp.py

def app(environ, start_response):
    start_response("200 OK", [("Content-Type", "text/plain; charset=utf-8")])
    return [b"Hello from WSGI!"]

if __name__ == "__main__":
    from wsgiref.simple_server import make_server
    server = make_server("localhost", 8000, app)
    print("Serveur WSGI lancé sur http://localhost:8000")
    server.serve_forever()

# Execução :
# python myapp.py
# Depois acesse http://localhost:8000

3. http.server para Prototipagem

O módulo http.server da stdlib oferece um servidor HTTP simples, útil para testar rapidamente um protótipo.

from http.server import HTTPServer, BaseHTTPRequestHandler
import json

class MonHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == "/":
            self.send_response(200)
            self.send_header("Content-Type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write(b"<h1>Accueil</h1>")
        elif self.path == "/api/info":
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            data = {"status": "ok", "message": "Réponse JSON"}
            self.wfile.write(json.dumps(data).encode("utf-8"))
        else:
            self.send_response(404)
            self.end_headers()
            self.wfile.write(b"Not found")

if __name__ == "__main__":
    server = HTTPServer(("localhost", 8000), MonHandler)
    print("Serveur lancé sur http://localhost:8000")
    server.serve_forever()

# Resultado : servidor simples, mas sem cache, com tratamento de erros mínimo, etc.

4. CGI vs WSGI vs ASGI: Comparação

AspectoCGIWSGIASGI
ProcessosNovo por requisiçãoUm processo persistenteUm/vários workers
ModeloSíncrono (bash/Perl/Python)Síncrono (Python)Assíncrono (async/await)
InicializaçãoMuito lenta (fork do SO)Rápida (função em memória)Rápida
Gerenciamento de estadoImpossívelPossível (cache, BD)Possível
EscalabilidadeRuimBoaExcelente
FrameworksNenhum (apenas cgi)Flask, DjangoFastAPI, Starlette
Exemplos de usoHistórico (anos 1990)Blogs, MVPs, aplicações clássicasAPIs em tempo real, WebSockets

5. Migração de CGI para Flask

Veja como refatorar um script CGI simples para Flask moderno.

Antes: CGI

#!/usr/bin/env python
# cgi-bin/calculator.cgi

import cgi

form = cgi.FieldStorage()
a = float(form.getvalue("a", 0))
b = float(form.getvalue("b", 0))
operation = form.getvalue("op", "add")

if operation == "add":
    result = a + b
elif operation == "subtract":
    result = a - b
else:
    result = 0

print("Content-Type: text/html; charset=utf-8")
print()
print(f"<h1>Résultat : {result}</h1>")

Depois: Flask

# app.py

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/calculate", methods=["GET", "POST"])
def calculate():
    a = float(request.args.get("a", 0))
    b = float(request.args.get("b", 0))
    operation = request.args.get("op", "add")
    
    if operation == "add":
        result = a + b
    elif operation == "subtract":
        result = a - b
    else:
        result = 0
    
    # Responder em JSON (moderno) em vez de HTML
    return jsonify({"a": a, "b": b, "operation": operation, "result": result})

if __name__ == "__main__":
    # pip install flask
    # python app.py
    # Acesse http://localhost:5000/calculate?a=10&b=5&op=add
    app.run(debug=True, port=5000)

# Vantagens :
# - Sem parsing manual
# - Resposta JSON estruturada
# - Tratamento de erros integrado
# - Facilmente extensível (middleware, templates, BD)

6. Boas Práticas

  • Abandone a CGI. O módulo cgi foi removido no Python 3.13. Não há nenhuma razão para continuar usando-o.
  • Escolha um framework WSGI (Flask, Django) ou ASGI (FastAPI, Starlette). Não escreva WSGI puro em produção.
  • Use um servidor de aplicação: Gunicorn (WSGI) ou Uvicorn (ASGI), não o servidor de desenvolvimento.
  • Versione suas dependências: pip freeze > requirements.txt ou use Poetry/Pipenv.
  • Gerencie o estado com um banco de dados, não em memória. Os workers são stateless.
  • Teste sua aplicação. Escreva testes unitários e de integração.

Conclusão

A CGI, embora histórica e elegante em sua época, tornou-se obsoleta. A WSGI trouxe eficiência graças a processos persistentes. Hoje, a ASGI e frameworks como FastAPI vão ainda mais longe com o assíncrono e o suporte nativo a WebSockets. Se você mantém código CGI legado, a migração para Flask ou FastAPI é uma etapa importante para manter a segurança, o desempenho e a manutenibilidade. Para novos projetos, comece diretamente com o FastAPI para aproveitar os padrões modernos e o desempenho ideal.

InSkillCoach

Sobre InSkillCoach

Especialista em treinamento e tecnologias

Coach especializado em tecnologias avançadas e IA, apoiado pela GNeurone Inc.

Certificações:

  • AWS Certified Solutions Architect – Professional
  • Certificações Google Cloud
  • Microsoft Certified: DevOps Engineer Expert
  • Certified Kubernetes Administrator (CKA)
  • CompTIA Security+
1.4k
118

Comentários

Os comentários são alimentados pelo GitHub Discussions

Conecte-se com o GitHub para participar da discussão

Link copiado!