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:
- Asynkront nätverk: Tornados kärna är byggd kring asynkron I/O, vilket gör att det effektivt kan hantera tusentals samtidiga anslutningar.
- Webbramverk: Det inkluderar funktioner som request handlers, routing, mallhantering och autentisering, vilket gör det till ett komplett webbramverk.
- Stöd för WebSockets: Tornado erbjuder utmärkt stöd för WebSockets, vilket möjliggör realtidskommunikation mellan servern och klienter.
- Lättviktigt och snabbt: Designat för prestanda är Tornado lättviktigt och effektivt, vilket minimerar overhead och maximerar genomströmning.
- Lätt att använda: Trots sina avancerade funktioner är Tornado relativt lätt att lära sig och använda, med ett tydligt och väldokumenterat API.
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:
- 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).
- Skapa en virtuell miljö (rekommenderas): Använd
venv
ellervirtualenv
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
- 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:
tornado.ioloop
: Kärn-händelseloopen som hanterar asynkrona operationer.tornado.web
: Tillhandahåller webbramverkets komponenter, såsom request handlers och routing.MainHandler
: En request handler som definierar hur inkommande HTTP-förfrågningar ska hanteras. Metodenget()
anropas för GET-förfrågningar.tornado.web.Application
: Skapar Tornado-applikationen och mappar URL-mönster till request handlers.app.listen(8888)
: Startar servern som lyssnar efter inkommande anslutningar på port 8888.tornado.ioloop.IOLoop.current().start()
: Startar händelseloopen, som bearbetar inkommande förfrågningar och hanterar asynkrona operationer.
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:
- Variabler:
{{ variable }}
- Kontrollflöde:
{% if condition %} ... {% else %} ... {% end %}
,{% for item in items %} ... {% end %}
- Funktioner:
{{ function(argument) }}
- Inkluderingar:
{% include "another_template.html" %}
- Escaping: Tornado escapar automatiskt HTML-entiteter för att förhindra cross-site scripting (XSS)-attacker. Du kan inaktivera escaping med
{% raw variable %}
.
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:
open()
: Anropas när en ny WebSocket-anslutning etableras.on_message(message)
: Anropas när ett meddelande tas emot från klienten.on_close()
: Anropas när WebSocket-anslutningen stängs.
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:
- Cookie-baserad autentisering: Lagra användaruppgifter i cookies.
- Tredjepartsautentisering (OAuth): Integrera med populära sociala medieplattformar som Google, Facebook och Twitter.
- API-nycklar: Använd API-nycklar för att autentisera API-förfrågningar.
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:
- Skydd mot Cross-Site Scripting (XSS): Tornado escapar automatiskt HTML-entiteter för att förhindra XSS-attacker. Använd alltid
render()
-metoden för att rendera mallar och undvik att generera HTML direkt i dina request handlers. - Skydd mot Cross-Site Request Forgery (CSRF): Aktivera CSRF-skydd i dina applikationsinställningar för att förhindra CSRF-attacker.
- HTTPS: Använd alltid HTTPS för att kryptera kommunikationen mellan servern och klienterna.
- Indatavalidering: Validera all användarinmatning för att förhindra injektionsattacker och andra sårbarheter.
- Regelbundna säkerhetsrevisioner: Genomför regelbundna säkerhetsrevisioner för att identifiera och åtgärda potentiella sårbarheter.
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:
- Använd en produktionsklar händelseloop: Använd en produktionsklar händelseloop som
uvloop
för förbättrad prestanda. - Aktivera gzip-komprimering: Aktivera gzip-komprimering för att minska storleken på HTTP-svar.
- Cacha statiska filer: Cacha statiska filer för att minska belastningen på servern.
- Övervaka prestanda: Övervaka prestandan för din applikation med verktyg som New Relic eller Prometheus.
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:
- **Teckenkodning:** Använd alltid UTF-8-kodning för att stödja ett brett utbud av tecken.
- **Datum- och tidsformatering:** Använd lokalspecifik datum- och tidsformatering. Pythons funktioner `strftime` och `strptime` kan användas med locale-inställningar.
- **Talformatering:** Använd lokalspecifik talformatering (t.ex. decimalavgränsare, tusentalsavgränsare). Modulen `locale` tillhandahåller funktioner för detta.
- **Valutaformatering:** Använd lokalspecifik valutaformatering. Överväg att använda ett bibliotek som `Babel` för mer avancerad valutahantering.
- **Höger-till-vänster (RTL)-språk:** Stöd RTL-språk som arabiska och hebreiska. Detta kan innebära att man spegelvänder layouten på din webbplats.
- **Översättningskvalitet:** Använd professionella översättare för att säkerställa korrekta och kulturellt anpassade översättningar. Maskinöversättning kan vara en bra utgångspunkt, men den kräver ofta mänsklig granskning.
- **Detektering av användarens locale:** Implementera robust detektering av locale baserat på användarens preferenser, webbläsarinställningar eller IP-adress. Ge användarna ett sätt att manuellt välja sitt föredragna språk.
- **Testning:** Testa din applikation noggrant med olika locales för att säkerställa att allt visas korrekt.
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!