Português

Uma exploração aprofundada do Tornado, um framework web Python e biblioteca de rede assíncrona. Aprenda a construir aplicações escaláveis e de alto desempenho com explicações detalhadas, exemplos e melhores práticas.

Documentação do Tornado: Um Guia Completo para Desenvolvedores de Todo o Mundo

O Tornado é um framework web Python e uma biblioteca de rede assíncrona, originalmente desenvolvido no FriendFeed. É particularmente adequado para long-polling, WebSockets e outras aplicações que exigem uma conexão de longa duração para cada utilizador. A sua E/S de rede não bloqueante torna-o extremamente escalável e uma escolha poderosa para construir aplicações web de alto desempenho. Este guia completo irá guiá-lo através dos conceitos centrais do Tornado e fornecer exemplos práticos para começar.

O que é o Tornado?

Na sua essência, o Tornado é um framework web e uma biblioteca de rede assíncrona. Ao contrário dos frameworks web síncronos tradicionais, o Tornado usa uma arquitetura baseada em loop de eventos e de thread único. Isto significa que ele pode lidar com muitas conexões simultâneas sem exigir um thread por conexão, tornando-o mais eficiente e escalável.

Principais Características do Tornado:

Configurando o Seu Ambiente Tornado

Antes de mergulhar no desenvolvimento com o Tornado, precisará de configurar o seu ambiente. Aqui está um guia passo a passo:

  1. Instalar o Python: Certifique-se de que tem o Python 3.6 ou superior instalado. Pode descarregá-lo do site oficial do Python (python.org).
  2. Criar um Ambiente Virtual (Recomendado): Use venv ou virtualenv para criar um ambiente isolado para o seu projeto:
    python3 -m venv myenv
    source myenv/bin/activate  # Em Linux/macOS
    myenv\Scripts\activate  # Em Windows
  3. Instalar o Tornado: Instale o Tornado usando o pip:
    pip install tornado

A Sua Primeira Aplicação Tornado

Vamos criar uma aplicação simples "Olá, Mundo!" com o Tornado. Crie um ficheiro chamado app.py e adicione o seguinte código:

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
 def get(self):
  self.write("Olá, Mundo!")

def make_app():
 return tornado.web.Application([
  (r"/", MainHandler),
 ])

if __name__ == "__main__":
 app = make_app()
 app.listen(8888)
 tornado.ioloop.IOLoop.current().start()

Agora, execute a aplicação a partir do seu terminal:

python app.py

Abra o seu navegador web e navegue para http://localhost:8888. Deverá ver a mensagem "Olá, Mundo!".

Explicação:

Manipuladores de Requisições e Roteamento

Os manipuladores de requisições são a base das aplicações web Tornado. Eles definem como lidar com as requisições HTTP recebidas com base no URL. O roteamento mapeia URLs para manipuladores de requisições específicos.

Definindo Manipuladores de Requisições:

Para criar um manipulador de requisições, herde de tornado.web.RequestHandler e implemente os métodos HTTP apropriados (get, post, put, delete, etc.).

class MyHandler(tornado.web.RequestHandler):
 def get(self):
  self.write("Esta é uma requisição GET.")

 def post(self):
  data = self.request.body.decode('utf-8')
  self.write(f"Dados POST recebidos: {data}")

Roteamento:

O roteamento é configurado ao criar a tornado.web.Application. Você fornece uma lista de tuplas, onde cada tupla contém um padrão de URL e o manipulador de requisição correspondente.

app = tornado.web.Application([
 (r"/", MainHandler),
 (r"/myhandler", MyHandler),
])

Padrões de URL:

Padrões de URL são expressões regulares. Pode usar grupos de expressões regulares para capturar partes do URL e passá-las como argumentos para os métodos do manipulador de requisição.

class UserHandler(tornado.web.RequestHandler):
 def get(self, user_id):
  self.write(f"ID do Utilizador: {user_id}")

app = tornado.web.Application([
 (r"/user/([0-9]+)", UserHandler),
])

Neste exemplo, /user/([0-9]+) corresponde a URLs como /user/123. A parte ([0-9]+) captura um ou mais dígitos e passa-os como o argumento user_id para o método get do UserHandler.

Templates

O Tornado inclui um motor de templates simples e eficiente. Os templates são usados para gerar HTML dinamicamente, separando a lógica de apresentação da lógica da aplicação.

Criando Templates:

Os templates são normalmente armazenados em ficheiros separados (ex: index.html). Aqui está um exemplo simples:

<!DOCTYPE html>
<html>
<head>
 <title>O Meu Site</title>
</head>
<body>
 <h1>Bem-vindo, {{ name }}!</h1>
 <p>Hoje é {{ today }}.</p>
</body>
</html>

{{ name }} e {{ today }} são marcadores de posição que serão substituídos por valores reais quando o template for renderizado.

Renderizando Templates:

Para renderizar um template, use o método render() no seu manipulador de requisição:

class TemplateHandler(tornado.web.RequestHandler):
 def get(self):
  name = "John Doe"
  today = "2023-10-27"
  self.render("index.html", name=name, today=today)

Certifique-se de que a configuração template_path está definida corretamente nas configurações da sua aplicação. Por defeito, o Tornado procura por templates num diretório chamado templates no mesmo diretório do seu ficheiro de aplicação.

app = tornado.web.Application([
 (r"/template", TemplateHandler),
], template_path="templates")

Sintaxe de Template:

Os templates do Tornado suportam várias funcionalidades, incluindo:

Operações Assíncronas

A força do Tornado reside nas suas capacidades assíncronas. As operações assíncronas permitem que a sua aplicação realize E/S não bloqueante, melhorando o desempenho e a escalabilidade. Isto é particularmente útil para tarefas que envolvem a espera por recursos externos, como consultas a bases de dados ou requisições de rede.

@tornado.gen.coroutine:

O decorador @tornado.gen.coroutine permite que escreva código assíncrono usando a palavra-chave yield. Isto faz com que o código assíncrono se pareça e se comporte mais como código síncrono, melhorando a legibilidade e a manutenibilidade.

import tornado.gen
import tornado.httpclient

class AsyncHandler(tornado.web.RequestHandler):
 @tornado.gen.coroutine
 def get(self):
  http_client = tornado.httpclient.AsyncHTTPClient()
  response = yield http_client.fetch("http://example.com")
  self.write(response.body.decode('utf-8'))

Neste exemplo, http_client.fetch() é uma operação assíncrona que retorna um Future. A palavra-chave yield suspende a execução da corrotina até que o Future seja resolvido. Assim que o Future é resolvido, a corrotina é retomada e o corpo da resposta é escrito para o cliente.

tornado.concurrent.Future:

Um Future representa o resultado de uma operação assíncrona que pode ainda não estar disponível. Pode usar objetos Future para encadear operações assíncronas e tratar erros.

tornado.ioloop.IOLoop:

O IOLoop é o coração do motor assíncrono do Tornado. Ele monitoriza descritores de ficheiros e sockets para eventos e despacha-os para os manipuladores apropriados. Normalmente, não precisa de interagir diretamente com o IOLoop, mas é importante entender o seu papel no tratamento de operações assíncronas.

WebSockets

O Tornado oferece um excelente suporte para WebSockets, permitindo a comunicação em tempo real entre o servidor e os clientes. Os WebSockets são ideais para aplicações que exigem comunicação bidirecional de baixa latência, como aplicações de chat, jogos online e painéis de controlo em tempo real.

Criando um Manipulador de WebSocket:

Para criar um manipulador de WebSocket, herde de tornado.websocket.WebSocketHandler e implemente os seguintes métodos:

import tornado.websocket

class WebSocketHandler(tornado.websocket.WebSocketHandler):
 def open(self):
  print("WebSocket aberto")

 def on_message(self, message):
  self.write_message(f"Você enviou: {message}")

 def on_close(self):
  print("WebSocket fechado")

 def check_origin(self, origin):
  return True # Ativar conexões WebSocket de origem cruzada

Integrando WebSockets na Sua Aplicação:

Adicione o manipulador de WebSocket à configuração de roteamento da sua aplicação:

app = tornado.web.Application([
 (r"/ws", WebSocketHandler),
])

Implementação do Lado do Cliente:

Do lado do cliente, pode usar JavaScript para estabelecer uma conexão WebSocket e enviar/receber mensagens:

const websocket = new WebSocket("ws://localhost:8888/ws");

websocket.onopen = () => {
 console.log("Conexão WebSocket estabelecida");
 websocket.send("Olá do cliente!");
};

websocket.onmessage = (event) => {
 console.log("Mensagem recebida:", event.data);
};

websocket.onclose = () => {
 console.log("Conexão WebSocket fechada");
};

Autenticação e Segurança

A segurança é um aspeto crítico do desenvolvimento de aplicações web. O Tornado fornece várias funcionalidades para ajudar a proteger as suas aplicações, incluindo autenticação, autorização e proteção contra vulnerabilidades web comuns.

Autenticação:

A autenticação é o processo de verificar a identidade de um utilizador. O Tornado oferece suporte integrado para vários esquemas de autenticação, incluindo:

Autorização:

A autorização é o processo de determinar se um utilizador tem permissão para aceder a um recurso específico. Pode implementar a lógica de autorização nos seus manipuladores de requisições para restringir o acesso com base em papéis ou permissões do utilizador.

Melhores Práticas de Segurança:

Implementação (Deployment)

A implementação de uma aplicação Tornado envolve vários passos, incluindo a configuração de um servidor web, a configuração de um gestor de processos e a otimização do desempenho.

Servidor Web:

Pode implementar o Tornado por trás de um servidor web como Nginx ou Apache. O servidor web atua como um proxy reverso, encaminhando as requisições recebidas para a aplicação Tornado.

Gestor de Processos:

Um gestor de processos como o Supervisor ou systemd pode ser usado para gerir o processo do Tornado, garantindo que seja reiniciado automaticamente em caso de falha.

Otimização de Desempenho:

Internacionalização (i18n) e Localização (l10n)

Ao construir aplicações para um público global, é importante considerar a internacionalização (i18n) e a localização (l10n). i18n é o processo de projetar uma aplicação para que possa ser adaptada a vários idiomas e regiões sem alterações de engenharia. l10n é o processo de adaptar uma aplicação internacionalizada para um idioma ou região específica, adicionando componentes específicos da localidade e traduzindo o texto.

Tornado e i18n/l10n

O próprio Tornado não possui bibliotecas i18n/l10n integradas. No entanto, pode integrar facilmente bibliotecas Python padrão como `gettext` ou frameworks mais sofisticados como o Babel para lidar com i18n/l10n na sua aplicação Tornado.

Exemplo usando `gettext`:

1. **Configure as suas localidades:** Crie diretórios para cada idioma que pretende suportar, contendo catálogos de mensagens (geralmente ficheiros `.mo`).

locales/
 en/LC_MESSAGES/messages.mo
 fr/LC_MESSAGES/messages.mo
 de/LC_MESSAGES/messages.mo

2. **Extraia as strings traduzíveis:** Use uma ferramenta como `xgettext` para extrair strings traduzíveis do seu código Python para um ficheiro `.po` (Portable Object). Este ficheiro conterá as strings originais e marcadores de posição para as traduções.

xgettext -d messages -o locales/messages.po your_tornado_app.py

3. **Traduza as strings:** Traduza as strings nos ficheiros `.po` para cada idioma.

4. **Compile as traduções:** Compile os ficheiros `.po` em ficheiros `.mo` (Machine Object) que são usados pelo `gettext` em tempo de execução.

msgfmt locales/fr/LC_MESSAGES/messages.po -o locales/fr/LC_MESSAGES/messages.mo

5. **Integre na sua aplicação Tornado:**

import gettext
import locale
import os
import tornado.web

class BaseHandler(tornado.web.RequestHandler):
 def initialize(self):
  try:
  locale.setlocale(locale.LC_ALL, self.get_user_locale().code)
  except locale.Error:
  # Lidar com casos em que a localidade não é suportada pelo sistema
  print(f"Localidade {self.get_user_locale().code} não suportada")

  translation = gettext.translation('messages', 'locales', languages=[self.get_user_locale().code])
  translation.install()
  self._ = translation.gettext

 def get_current_user_locale(self):
  # Lógica para determinar a localidade do utilizador (ex: do cabeçalho Accept-Language, configurações do utilizador, etc.)
  # Este é um exemplo simplificado - você precisará de uma solução mais robusta
  accept_language = self.request.headers.get('Accept-Language', 'en')
  return tornado.locale.get(accept_language.split(',')[0].split(';')[0])

class MainHandler(BaseHandler):
 def get(self):
  self.render("index.html", _=self._)

settings = {
 "template_path": os.path.join(os.path.dirname(__file__), "templates"),
}

app = tornado.web.Application([
 (r"/", MainHandler),
], **settings)

6. **Modifique os seus templates:** Use a função `_()` (vinculada a `gettext.gettext`) para marcar strings para tradução nos seus templates.

<h1>{{ _("Bem-vindo ao nosso site!") }}</h1>
<p>{{ _("Este é um parágrafo traduzido.") }}</p>

Considerações Importantes para Públicos Globais:

Tópicos Avançados

Páginas de Erro Personalizadas:

Pode personalizar as páginas de erro que o Tornado exibe quando ocorre um erro. Isto permite-lhe fornecer uma experiência mais amigável ao utilizador e incluir informações de depuração.

Configurações Personalizadas:

Pode definir configurações personalizadas na configuração da sua aplicação e acedê-las nos seus manipuladores de requisições. Isto é útil para armazenar parâmetros específicos da aplicação, como strings de conexão de base de dados ou chaves de API.

Testes:

Teste exaustivamente as suas aplicações Tornado para garantir que estão a funcionar correta e seguramente. Use testes unitários, testes de integração e testes de ponta a ponta para cobrir todos os aspetos da sua aplicação.

Conclusão

O Tornado é um framework web poderoso e versátil, bem adequado para construir aplicações web escaláveis e de alto desempenho. A sua arquitetura assíncrona, suporte a WebSockets e API fácil de usar tornam-no uma escolha popular para desenvolvedores em todo o mundo. Seguindo as diretrizes e exemplos deste guia completo, pode começar a construir as suas próprias aplicações Tornado e aproveitar as suas muitas funcionalidades.

Lembre-se de consultar a documentação oficial do Tornado para obter as informações mais atualizadas e as melhores práticas. Boas codificações!

Documentação do Tornado: Um Guia Completo para Desenvolvedores de Todo o Mundo | MLOG