Svenska

En djupgående utforskning av Tornado, ett webbramverk och asynkront nätverksbibliotek för Python. Lär dig bygga skalbara, högpresterande applikationer med detaljerade förklaringar, exempel och bästa praxis.

Tornado-dokumentation: En omfattande guide för utvecklare världen över

Tornado är ett webbramverk och asynkront nätverksbibliotek för Python, ursprungligen utvecklat på FriendFeed. Det är särskilt väl lämpat för long-polling, WebSockets och andra applikationer som kräver en långvarig anslutning till varje användare. Dess icke-blockerande nätverks-I/O gör det extremt skalbart och ett kraftfullt val för att bygga högpresterande webbapplikationer. Denna omfattande guide kommer att leda dig genom Tornados kärnkoncept och ge praktiska exempel för att komma igång.

Vad är Tornado?

I grunden är Tornado ett webbramverk och asynkront nätverksbibliotek. Till skillnad från traditionella synkrona webbramverk använder Tornado en entrådad, händelseloop-baserad arkitektur. Detta innebär att det kan hantera många samtidiga anslutningar utan att kräva en tråd per anslutning, vilket gör det mer effektivt och skalbart.

Nyckelfunktioner i Tornado:

Konfigurera din Tornado-miljö

Innan du dyker in i Tornado-utveckling måste du konfigurera din miljö. Här är en steg-för-steg-guide:

  1. Installera Python: Se till att du har Python 3.6 eller högre installerat. Du kan ladda ner det från den officiella Python-webbplatsen (python.org).
  2. Skapa en virtuell miljö (rekommenderas): Använd venv eller virtualenv för att skapa en isolerad miljö för ditt projekt:
    python3 -m venv myenv
    source myenv/bin/activate  # På Linux/macOS
    myenv\Scripts\activate  # På Windows
  3. Installera Tornado: Installera Tornado med pip:
    pip install tornado

Din första Tornado-applikation

Låt oss skapa en enkel "Hej, Världen!"-applikation med Tornado. Skapa en fil med namnet app.py och lägg till följande kod:

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
 def get(self):
  self.write("Hej, Världen!")

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

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

Kör nu applikationen från din terminal:

python app.py

Öppna din webbläsare och navigera till http://localhost:8888. Du bör se meddelandet "Hej, Världen!".

Förklaring:

Request Handlers och Routing

Request handlers är grunden för Tornado-webbapplikationer. De definierar hur man hanterar inkommande HTTP-förfrågningar baserat på URL:en. Routing mappar URL:er till specifika request handlers.

Definiera Request Handlers:

För att skapa en request handler, subklassa tornado.web.RequestHandler och implementera lämpliga HTTP-metoder (get, post, put, delete, etc.).

class MyHandler(tornado.web.RequestHandler):
 def get(self):
  self.write("Detta är en GET-förfrågan.")

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

Routing:

Routing konfigureras när tornado.web.Application skapas. Du anger en lista med tupler, där varje tupel innehåller ett URL-mönster och motsvarande request handler.

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

URL-mönster:

URL-mönster är reguljära uttryck. Du kan använda grupper i reguljära uttryck för att fånga delar av URL:en och skicka dem som argument till request handler-metoderna.

class UserHandler(tornado.web.RequestHandler):
 def get(self, user_id):
  self.write(f"Användar-ID: {user_id}")

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

I detta exempel matchar /user/([0-9]+) URL:er som /user/123. Delen ([0-9]+) fångar en eller flera siffror och skickar dem som argumentet user_id till get-metoden i UserHandler.

Mallhantering (Templating)

Tornado inkluderar en enkel och effektiv mallmotor. Mallar används för att generera HTML dynamiskt och separerar presentationslogik från applikationslogik.

Skapa mallar:

Mallar lagras vanligtvis i separata filer (t.ex. index.html). Här är ett enkelt exempel:

<!DOCTYPE html>
<html>
<head>
 <title>Min webbplats</title>
</head>
<body>
 <h1>Välkommen, {{ name }}!</h1>
 <p>Idag är det {{ today }}.</p>
</body>
</html>

{{ name }} och {{ today }} är platshållare som kommer att ersättas med faktiska värden när mallen renderas.

Rendera mallar:

För att rendera en mall, använd render()-metoden i din request handler:

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

Se till att inställningen template_path är korrekt konfigurerad i dina applikationsinställningar. Som standard letar Tornado efter mallar i en katalog med namnet templates i samma katalog som din applikationsfil.

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

Mallsyntax:

Tornado-mallar stöder olika funktioner, inklusive:

Asynkrona operationer

Tornados styrka ligger i dess asynkrona kapabiliteter. Asynkrona operationer låter din applikation utföra icke-blockerande I/O, vilket förbättrar prestanda och skalbarhet. Detta är särskilt användbart för uppgifter som involverar väntan på externa resurser, såsom databasfrågor eller nätverksanrop.

@tornado.gen.coroutine:

Dekoratorn @tornado.gen.coroutine låter dig skriva asynkron kod med nyckelordet yield. Detta gör att asynkron kod ser ut och beter sig mer som synkron kod, vilket förbättrar läsbarheten och underhållbarheten.

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'))

I detta exempel är http_client.fetch() en asynkron operation som returnerar en Future. Nyckelordet yield pausar exekveringen av coroutinen tills Future-objektet är löst. När Future-objektet är löst återupptas coroutinen och svarskroppen skrivs till klienten.

tornado.concurrent.Future:

En Future representerar resultatet av en asynkron operation som kanske inte är tillgängligt ännu. Du kan använda Future-objekt för att kedja samman asynkrona operationer och hantera fel.

tornado.ioloop.IOLoop:

IOLoop är hjärtat i Tornados asynkrona motor. Den övervakar filbeskrivare och sockets för händelser och skickar dem till lämpliga handlers. Du behöver vanligtvis inte interagera med IOLoop direkt, men det är viktigt att förstå dess roll i hanteringen av asynkrona operationer.

WebSockets

Tornado erbjuder utmärkt stöd för WebSockets, vilket möjliggör realtidskommunikation mellan servern och klienter. WebSockets är idealiska för applikationer som kräver dubbelriktad kommunikation med låg latens, såsom chattapplikationer, onlinespel och realtids-dashboards.

Skapa en WebSocket Handler:

För att skapa en WebSocket-handler, subklassa tornado.websocket.WebSocketHandler och implementera följande metoder:

import tornado.websocket

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

 def on_message(self, message):
  self.write_message(f"Du skickade: {message}")

 def on_close(self):
  print("WebSocket stängd")

 def check_origin(self, origin):
  return True # Aktivera cross-origin WebSocket-anslutningar

Integrera WebSockets i din applikation:

Lägg till WebSocket-handlern i din applikations routing-konfiguration:

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

Implementation på klientsidan:

På klientsidan kan du använda JavaScript för att etablera en WebSocket-anslutning och skicka/ta emot meddelanden:

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

websocket.onopen = () => {
 console.log("WebSocket-anslutning etablerad");
 websocket.send("Hej från klienten!");
};

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

websocket.onclose = () => {
 console.log("WebSocket-anslutning stängd");
};

Autentisering och säkerhet

Säkerhet är en kritisk aspekt av webbapplikationsutveckling. Tornado tillhandahåller flera funktioner för att hjälpa dig att säkra dina applikationer, inklusive autentisering, auktorisering och skydd mot vanliga webbsårbarheter.

Autentisering:

Autentisering är processen att verifiera en användares identitet. Tornado har inbyggt stöd för olika autentiseringsscheman, inklusive:

Auktorisering:

Auktorisering är processen att avgöra om en användare har behörighet att komma åt en viss resurs. Du kan implementera auktoriseringslogik i dina request handlers för att begränsa åtkomst baserat på användarroller eller behörigheter.

Bästa praxis för säkerhet:

Driftsättning (Deployment)

Att driftsätta en Tornado-applikation innefattar flera steg, inklusive att konfigurera en webbserver, sätta upp en processhanterare och optimera prestanda.

Webbserver:

Du kan driftsätta Tornado bakom en webbserver som Nginx eller Apache. Webbservern fungerar som en omvänd proxy och vidarebefordrar inkommande förfrågningar till Tornado-applikationen.

Processhanterare:

En processhanterare som Supervisor eller systemd kan användas för att hantera Tornado-processen och säkerställa att den startas om automatiskt om den kraschar.

Prestandaoptimering:

Internationalisering (i18n) och lokalisering (l10n)

När man bygger applikationer för en global publik är det viktigt att ta hänsyn till internationalisering (i18n) och lokalisering (l10n). i18n är processen att designa en applikation så att den kan anpassas till olika språk och regioner utan tekniska ändringar. l10n är processen att anpassa en internationaliserad applikation för ett specifikt språk eller en specifik region genom att lägga till lokalspecifika komponenter och översätta text.

Tornado och i18n/l10n

Tornado har inga inbyggda i18n/l10n-bibliotek. Däremot kan du enkelt integrera standardbibliotek i Python som `gettext` eller mer sofistikerade ramverk som Babel för att hantera i18n/l10n i din Tornado-applikation.

Exempel med gettext:

1. **Konfigurera dina locales:** Skapa kataloger för varje språk du vill stödja, innehållande meddelandekataloger (vanligtvis `.mo`-filer).

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

2. **Extrahera översättningsbara strängar:** Använd ett verktyg som xgettext för att extrahera översättningsbara strängar från din Python-kod till en `.po`-fil (Portable Object). Denna fil kommer att innehålla originalsträngarna och platshållare för översättningar.

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

3. **Översätt strängarna:** Översätt strängarna i `.po`-filerna för varje språk.

4. **Kompilera översättningarna:** Kompilera `.po`-filerna till `.mo`-filer (Machine Object) som används av `gettext` vid körtid.

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

5. **Integrera i din Tornado-applikation:**

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:
  # Hantera fall där locale inte stöds av systemet
  print(f"Locale {self.get_user_locale().code} stöds inte")

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

 def get_current_user_locale(self):
  # Logik för att bestämma användarens locale (t.ex. från Accept-Language-header, användarinställningar, etc.)
  # Detta är ett förenklat exempel - du behöver en mer robust lösning
  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. **Modifiera dina mallar:** Använd funktionen `_()` (bunden till `gettext.gettext`) för att markera strängar för översättning i dina mallar.

<h1>{{ _("Välkommen till vår webbplats!") }}</h1>
<p>{{ _("Detta är ett översatt stycke.") }}</p>

Viktiga överväganden för en global publik:

Avancerade ämnen

Anpassade felsidor:

Du kan anpassa felsidorna som Tornado visar när ett fel uppstår. Detta gör att du kan ge en mer användarvänlig upplevelse och inkludera felsökningsinformation.

Anpassade inställningar:

Du kan definiera anpassade inställningar i din applikationskonfiguration och komma åt dem i dina request handlers. Detta är användbart för att lagra applikationsspecifika parametrar, såsom anslutningssträngar till databaser eller API-nycklar.

Testning:

Testa dina Tornado-applikationer noggrant för att säkerställa att de fungerar korrekt och säkert. Använd enhetstester, integrationstester och end-to-end-tester för att täcka alla aspekter av din applikation.

Slutsats

Tornado är ett kraftfullt och mångsidigt webbramverk som är väl lämpat för att bygga skalbara, högpresterande webbapplikationer. Dess asynkrona arkitektur, stöd för WebSockets och lättanvända API gör det till ett populärt val för utvecklare världen över. Genom att följa riktlinjerna och exemplen i denna omfattande guide kan du börja bygga dina egna Tornado-applikationer och dra nytta av dess många funktioner.

Kom ihåg att konsultera den officiella Tornado-dokumentationen för den mest uppdaterade informationen och bästa praxis. Lycka till med kodningen!