Hrvatski

Dubinska analiza Tornada, Python web okvira i asinkrone mrežne biblioteke. Naučite kako izraditi skalabilne aplikacije visokih performansi uz detaljna objašnjenja, primjere i najbolje prakse.

Tornado dokumentacija: Sveobuhvatni vodič za programere širom svijeta

Tornado je Python web okvir i asinkrona mrežna biblioteka, izvorno razvijena u FriendFeedu. Posebno je prikladan za long-polling, WebSockets i druge aplikacije koje zahtijevaju dugotrajnu vezu sa svakim korisnikom. Njegov neblokirajući mrežni I/O čini ga izuzetno skalabilnim i moćnim izborom za izradu web aplikacija visokih performansi. Ovaj sveobuhvatni vodič provest će vas kroz temeljne koncepte Tornada i pružiti praktične primjere za početak.

Što je Tornado?

U svojoj suštini, Tornado je web okvir i asinkrona mrežna biblioteka. Za razliku od tradicionalnih sinkronih web okvira, Tornado koristi jednorednu arhitekturu temeljenu na petlji događaja (event-loop). To znači da može obraditi mnogo istovremenih veza bez potrebe za jednom dretvom (thread) po vezi, što ga čini učinkovitijim i skalabilnijim.

Ključne značajke Tornada:

Postavljanje vašeg Tornado okruženja

Prije nego što uronite u razvoj s Tornadom, trebate postaviti svoje okruženje. Evo vodiča korak po korak:

  1. Instalirajte Python: Provjerite imate li instaliran Python 3.6 ili noviji. Možete ga preuzeti sa službene Python web stranice (python.org).
  2. Kreirajte virtualno okruženje (preporučeno): Koristite venv ili virtualenv za stvaranje izoliranog okruženja za vaš projekt:
    python3 -m venv myenv
    source myenv/bin/activate  # Na Linuxu/macOS-u
    myenv\Scripts\activate  # Na Windowsima
  3. Instalirajte Tornado: Instalirajte Tornado pomoću pipa:
    pip install tornado

Vaša prva Tornado aplikacija

Kreirajmo jednostavnu "Hello, World!" aplikaciju s Tornadom. Stvorite datoteku naziva app.py i dodajte sljedeći kod:

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
 def get(self):
  self.write("Hello, World!")

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

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

Sada pokrenite aplikaciju iz svog terminala:

python app.py

Otvorite svoj web preglednik i idite na http://localhost:8888. Trebali biste vidjeti poruku "Hello, World!".

Objašnjenje:

Rukovatelji zahtjevima i usmjeravanje

Rukovatelji zahtjevima temelj su Tornado web aplikacija. Oni definiraju kako se obrađuju dolazni HTTP zahtjevi na temelju URL-a. Usmjeravanje (routing) mapira URL-ove na određene rukovatelje zahtjevima.

Definiranje rukovatelja zahtjevima:

Da biste stvorili rukovatelja zahtjevima, naslijedite klasu tornado.web.RequestHandler i implementirajte odgovarajuće HTTP metode (get, post, put, delete, itd.).

class MyHandler(tornado.web.RequestHandler):
 def get(self):
  self.write("Ovo je GET zahtjev.")

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

Usmjeravanje:

Usmjeravanje se konfigurira prilikom stvaranja tornado.web.Application. Pružate popis n-torki, gdje svaka n-torka sadrži URL uzorak i odgovarajućeg rukovatelja zahtjevima.

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

URL uzorci:

URL uzorci su regularni izrazi. Možete koristiti grupe regularnih izraza za hvatanje dijelova URL-a i njihovo prosljeđivanje kao argumenata metodama rukovatelja zahtjevima.

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

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

U ovom primjeru, /user/([0-9]+) odgovara URL-ovima poput /user/123. Dio ([0-9]+) hvata jednu ili više znamenki i prosljeđuje ih kao argument user_id metodi get klase UserHandler.

Predlošci (Templating)

Tornado uključuje jednostavan i učinkovit sustav predložaka. Predlošci se koriste za dinamičko generiranje HTML-a, odvajajući logiku prezentacije od logike aplikacije.

Stvaranje predložaka:

Predlošci se obično pohranjuju u zasebnim datotekama (npr. index.html). Evo jednostavnog primjera:

<!DOCTYPE html>
<html>
<head>
 <title>Moja web stranica</title>
</head>
<body>
 <h1>Dobrodošli, {{ name }}!</h1>
 <p>Danas je {{ today }}.</p>
</body>
</html>

{{ name }} i {{ today }} su rezervirana mjesta koja će biti zamijenjena stvarnim vrijednostima prilikom iscrtavanja predloška.

Iscrtavanje predložaka:

Za iscrtavanje predloška koristite metodu render() u svom rukovatelju zahtjevima:

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

Provjerite je li postavka template_path ispravno konfigurirana u postavkama vaše aplikacije. Prema zadanim postavkama, Tornado traži predloške u direktoriju nazvanom templates u istom direktoriju kao i vaša aplikacijska datoteka.

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

Sintaksa predložaka:

Tornado predlošci podržavaju različite značajke, uključujući:

Asinkrone operacije

Snaga Tornada leži u njegovim asinkronim sposobnostima. Asinkrone operacije omogućuju vašoj aplikaciji izvođenje neblokirajućeg I/O-a, poboljšavajući performanse i skalabilnost. To je posebno korisno za zadatke koji uključuju čekanje na vanjske resurse, kao što su upiti u bazu podataka ili mrežni zahtjevi.

@tornado.gen.coroutine:

Dekorator @tornado.gen.coroutine omogućuje vam pisanje asinkronog koda pomoću ključne riječi yield. To čini da asinkroni kod izgleda i ponaša se više kao sinkroni kod, poboljšavajući čitljivost i održivost.

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

U ovom primjeru, http_client.fetch() je asinkrona operacija koja vraća Future. Ključna riječ yield obustavlja izvršenje korutine dok se Future ne razriješi. Jednom kada je Future razriješen, korutina se nastavlja, a tijelo odgovora se ispisuje klijentu.

tornado.concurrent.Future:

Future predstavlja rezultat asinkrone operacije koji možda još nije dostupan. Možete koristiti Future objekte za lančano povezivanje asinkronih operacija i rukovanje pogreškama.

tornado.ioloop.IOLoop:

IOLoop je srce Tornadovog asinkronog mehanizma. Nadgleda deskriptore datoteka i sockete za događaje te ih prosljeđuje odgovarajućim rukovateljima. Obično ne morate izravno komunicirati s IOLoop, ali važno je razumjeti njegovu ulogu u rukovanju asinkronim operacijama.

WebSockets

Tornado pruža izvrsnu podršku za WebSockets, omogućujući komunikaciju u stvarnom vremenu između poslužitelja i klijenata. WebSockets su idealni za aplikacije koje zahtijevaju dvosmjernu komunikaciju s malom latencijom, kao što su chat aplikacije, online igre i nadzorne ploče u stvarnom vremenu.

Stvaranje WebSocket rukovatelja:

Da biste stvorili WebSocket rukovatelja, naslijedite klasu tornado.websocket.WebSocketHandler i implementirajte sljedeće metode:

import tornado.websocket

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

 def on_message(self, message):
  self.write_message(f"Poslali ste: {message}")

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

 def check_origin(self, origin):
  return True # Omogući WebSocket veze s različitih izvora

Integriranje WebSocketsa u vašu aplikaciju:

Dodajte WebSocket rukovatelja u konfiguraciju usmjeravanja vaše aplikacije:

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

Implementacija na strani klijenta:

Na strani klijenta možete koristiti JavaScript za uspostavljanje WebSocket veze i slanje/primanje poruka:

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

websocket.onopen = () => {
 console.log("WebSocket veza uspostavljena");
 websocket.send("Pozdrav s klijenta!");
};

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

websocket.onclose = () => {
 console.log("WebSocket veza zatvorena");
};

Autentifikacija i sigurnost

Sigurnost je ključan aspekt razvoja web aplikacija. Tornado pruža nekoliko značajki koje vam pomažu osigurati vaše aplikacije, uključujući autentifikaciju, autorizaciju i zaštitu od uobičajenih web ranjivosti.

Autentifikacija:

Autentifikacija je proces provjere identiteta korisnika. Tornado pruža ugrađenu podršku za različite sheme autentifikacije, uključujući:

Autorizacija:

Autorizacija je proces određivanja ima li korisnik dopuštenje za pristup određenom resursu. Možete implementirati logiku autorizacije u svojim rukovateljima zahtjevima kako biste ograničili pristup na temelju korisničkih uloga ili dopuštenja.

Najbolje sigurnosne prakse:

Implementacija (Deployment)

Implementacija Tornado aplikacije uključuje nekoliko koraka, uključujući konfiguriranje web poslužitelja, postavljanje upravitelja procesa i optimizaciju performansi.

Web poslužitelj:

Možete implementirati Tornado iza web poslužitelja poput Nginxa ili Apachea. Web poslužitelj djeluje kao obrnuti proxy (reverse proxy), prosljeđujući dolazne zahtjeve Tornado aplikaciji.

Upravitelj procesa:

Upravitelj procesa poput Supervisora ili systemd može se koristiti za upravljanje Tornado procesom, osiguravajući da se automatski ponovno pokrene ako se sruši.

Optimizacija performansi:

Internacionalizacija (i18n) i lokalizacija (l10n)

Prilikom izrade aplikacija za globalnu publiku, važno je uzeti u obzir internacionalizaciju (i18n) i lokalizaciju (l10n). i18n je proces dizajniranja aplikacije tako da se može prilagoditi različitim jezicima i regijama bez inženjerskih promjena. l10n je proces prilagodbe internacionalizirane aplikacije za određeni jezik ili regiju dodavanjem lokalno specifičnih komponenti i prevođenjem teksta.

Tornado i i18n/l10n

Sam Tornado nema ugrađene i18n/l10n biblioteke. Međutim, možete jednostavno integrirati standardne Python biblioteke poput `gettext` ili sofisticiranije okvire poput Babela za rukovanje i18n/l10n unutar vaše Tornado aplikacije.

Primjer korištenja `gettext`:

1. **Postavite svoje lokalne postavke (locales):** Stvorite direktorije za svaki jezik koji želite podržati, koji sadrže kataloge poruka (obično `.mo` datoteke).

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

2. **Izdvojite prevodive nizove:** Koristite alat poput `xgettext` za izdvajanje prevodivih nizova iz vašeg Python koda u `.po` datoteku (Portable Object). Ova datoteka će sadržavati originalne nizove i rezervirana mjesta za prijevode.

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

3. **Prevedite nizove:** Prevedite nizove u `.po` datotekama za svaki jezik.

4. **Kompajlirajte prijevode:** Kompajlirajte `.po` datoteke u `.mo` datoteke (Machine Object) koje `gettext` koristi pri izvođenju.

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

5. **Integrirajte u svoju Tornado aplikaciju:**

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:
  # Rješavanje slučajeva gdje lokalne postavke nisu podržane od strane sustava
  print(f"Lokalne postavke {self.get_user_locale().code} nisu podržane")

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

 def get_current_user_locale(self):
  # Logika za određivanje lokalnih postavki korisnika (npr. iz Accept-Language zaglavlja, korisničkih postavki, itd.)
  # Ovo je pojednostavljen primjer - trebat će vam robusnije rješenje
  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. **Izmijenite svoje predloške:** Koristite funkciju `_()` (povezanu s `gettext.gettext`) za označavanje nizova za prevođenje u vašim predlošcima.

<h1>{{ _("Dobrodošli na našu web stranicu!") }}</h1>
<p>{{ _("Ovo je prevedeni odlomak.") }}</p>

Važna razmatranja za globalnu publiku:

Napredne teme

Prilagođene stranice s greškama:

Možete prilagoditi stranice s greškama koje Tornado prikazuje kada dođe do greške. To vam omogućuje da pružite korisnički prihvatljivije iskustvo i uključite informacije za otklanjanje grešaka.

Prilagođene postavke:

Možete definirati prilagođene postavke u konfiguraciji svoje aplikacije i pristupati im u svojim rukovateljima zahtjevima. To je korisno za pohranu parametara specifičnih za aplikaciju, kao što su nizovi za povezivanje s bazom podataka ili API ključevi.

Testiranje:

Temeljito testirajte svoje Tornado aplikacije kako biste osigurali da funkcioniraju ispravno i sigurno. Koristite jedinične testove, integracijske testove i end-to-end testove kako biste pokrili sve aspekte vaše aplikacije.

Zaključak

Tornado je moćan i svestran web okvir koji je vrlo prikladan za izradu skalabilnih web aplikacija visokih performansi. Njegova asinkrona arhitektura, podrška za WebSocket i jednostavan API čine ga popularnim izborom za programere širom svijeta. Slijedeći smjernice i primjere u ovom sveobuhvatnom vodiču, možete početi graditi vlastite Tornado aplikacije i iskoristiti njegove brojne značajke.

Ne zaboravite konzultirati službenu Tornado dokumentaciju za najnovije informacije i najbolje prakse. Sretno kodiranje!