חקירה מעמיקה של Tornado, פריימוורק ווב וספריית רשת אסינכרונית של פייתון. למדו כיצד לבנות יישומים סקלביליים ובעלי ביצועים גבוהים עם הסברים מפורטים, דוגמאות ושיטות עבודה מומלצות.
תיעוד Tornado: מדריך מקיף למפתחים ברחבי העולם
Tornado הוא פריימוורק ווב וספריית רשת אסינכרונית של פייתון, שפותחה במקור ב-FriendFeed. היא מתאימה במיוחד עבור long-polling, WebSockets, ויישומים אחרים הדורשים חיבור ארוך טווח לכל משתמש. קלט/פלט הרשת הלא-חוסם שלה הופך אותה לסקלבילית במיוחד ולבחירה עוצמתית לבניית יישומי ווב בעלי ביצועים גבוהים. מדריך מקיף זה ילווה אתכם דרך מושגי הליבה של Tornado ויספק דוגמאות מעשיות כדי להתחיל.
מהו Tornado?
בבסיסו, Tornado הוא פריימוורק ווב וספריית רשת אסינכרונית. בניגוד לפריימוורקים סינכרוניים מסורתיים, Tornado משתמש בארכיטקטורה מבוססת לולאת אירועים (event loop) עם תהליכון יחיד. משמעות הדבר היא שהוא יכול לטפל בחיבורים מקבילים רבים מבלי לדרוש תהליכון לכל חיבור, מה שהופך אותו ליעיל וסקלבילי יותר.
תכונות מפתח של Tornado:
- רשת אסינכרונית: ליבת Tornado בנויה סביב קלט/פלט אסינכרוני, המאפשר לו לטפל באלפי חיבורים מקבילים ביעילות.
- פריימוורק ווב: הוא כולל תכונות כמו מטפלי בקשות (request handlers), ניתוב, תבניות ואימות, מה שהופך אותו לפריימוורק ווב שלם.
- תמיכה ב-WebSocket: Tornado מספק תמיכה מצוינת ב-WebSockets, המאפשרת תקשורת בזמן אמת בין השרת ללקוחות.
- קל משקל ומהיר: Tornado תוכנן לביצועים, הוא קל משקל ויעיל, ממזער תקורה וממקסם תפוקה.
- קל לשימוש: למרות תכונותיו המתקדמות, Tornado קל יחסית ללמידה ולשימוש, עם API ברור ומתועד היטב.
הגדרת סביבת Tornado שלכם
לפני שצוללים לפיתוח עם Tornado, תצטרכו להגדיר את הסביבה שלכם. הנה מדריך שלב אחר שלב:
- התקינו פייתון: ודאו שמותקן אצלכם פייתון 3.6 ומעלה. ניתן להוריד אותו מאתר פייתון הרשמי (python.org).
- צרו סביבה וירטואלית (מומלץ): השתמשו ב-
venv
אוvirtualenv
כדי ליצור סביבה מבודדת עבור הפרויקט שלכם:python3 -m venv myenv source myenv/bin/activate # On Linux/macOS myenv\Scripts\activate # On Windows
- התקינו את Tornado: התקינו את Tornado באמצעות pip:
pip install tornado
יישום Tornado הראשון שלכם
בואו ניצור יישום "Hello, World!" פשוט עם Tornado. צרו קובץ בשם app.py
והוסיפו את הקוד הבא:
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()
כעת, הריצו את היישום מהטרמינל שלכם:
python app.py
פתחו את דפדפן האינטרנט שלכם ונווטו אל http://localhost:8888
. אתם אמורים לראות את ההודעה "Hello, World!".
הסבר:
tornado.ioloop
: לולאת האירועים המרכזית שמטפלת בפעולות אסינכרוניות.tornado.web
: מספק את רכיבי פריימוורק הווב, כגון מטפלי בקשות וניתוב.MainHandler
: מטפל בקשות שמגדיר כיצד לטפל בבקשות HTTP נכנסות. מתודתget()
נקראת עבור בקשות GET.tornado.web.Application
: יוצר את יישום ה-Tornado, וממפה תבניות URL למטפלי בקשות.app.listen(8888)
: מפעיל את השרת, המאזין לחיבורים נכנסים בפורט 8888.tornado.ioloop.IOLoop.current().start()
: מפעיל את לולאת האירועים, אשר מעבדת בקשות נכנסות ומטפלת בפעולות אסינכרוניות.
מטפלי בקשות וניתוב
מטפלי בקשות הם הבסיס של יישומי ווב ב-Tornado. הם מגדירים כיצד לטפל בבקשות HTTP נכנסות על בסיס ה-URL. ניתוב ממפה כתובות URL למטפלי בקשות ספציפיים.
הגדרת מטפלי בקשות:
כדי ליצור מטפל בקשות, יש לרשת מ-tornado.web.RequestHandler
ולממש את מתודות ה-HTTP המתאימות (get
, post
, put
, delete
, וכו').
class MyHandler(tornado.web.RequestHandler):
def get(self):
self.write("This is a GET request.")
def post(self):
data = self.request.body.decode('utf-8')
self.write(f"Received POST data: {data}")
ניתוב:
הניתוב מוגדר בעת יצירת tornado.web.Application
. אתם מספקים רשימה של tuples, כאשר כל tuple מכיל תבנית URL ואת מטפל הבקשות המתאים.
app = tornado.web.Application([
(r"/", MainHandler),
(r"/myhandler", MyHandler),
])
תבניות URL:
תבניות URL הן ביטויים רגולריים. ניתן להשתמש בקבוצות של ביטויים רגולריים כדי ללכוד חלקים מה-URL ולהעביר אותם כארגומנטים למתודות של מטפל הבקשות.
class UserHandler(tornado.web.RequestHandler):
def get(self, user_id):
self.write(f"User ID: {user_id}")
app = tornado.web.Application([
(r"/user/([0-9]+)", UserHandler),
])
בדוגמה זו, /user/([0-9]+)
מתאים לכתובות URL כמו /user/123
. החלק ([0-9]+)
לוכד ספרה אחת או יותר ומעביר אותן כארגומנט user_id
למתודת ה-get
של UserHandler
.
תבניות (Templating)
Tornado כולל מנוע תבניות פשוט ויעיל. תבניות משמשות ליצירת HTML באופן דינמי, תוך הפרדת לוגיקת התצוגה מלוגיקת היישום.
יצירת תבניות:
תבניות מאוחסנות בדרך כלל בקבצים נפרדים (למשל, index.html
). הנה דוגמה פשוטה:
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
</head>
<body>
<h1>Welcome, {{ name }}!</h1>
<p>Today is {{ today }}.</p>
</body>
</html>
ה-{{ name }}
וה-{{ today }}
הם מצייני מיקום שיוחלפו בערכים ממשיים כאשר התבנית תעובד.
עיבוד תבניות:
כדי לעבד תבנית, השתמשו במתודת render()
במטפל הבקשות שלכם:
class TemplateHandler(tornado.web.RequestHandler):
def get(self):
name = "John Doe"
today = "2023-10-27"
self.render("index.html", name=name, today=today)
ודאו שההגדרה template_path
מוגדרת כראוי בהגדרות היישום שלכם. כברירת מחדל, Tornado מחפש תבניות בספרייה בשם templates
באותה ספרייה של קובץ היישום שלכם.
app = tornado.web.Application([
(r"/template", TemplateHandler),
], template_path="templates")
תחביר תבניות:
תבניות Tornado תומכות בתכונות שונות, כולל:
- משתנים:
{{ variable }}
- בקרת זרימה:
{% if condition %} ... {% else %} ... {% end %}
,{% for item in items %} ... {% end %}
- פונקציות:
{{ function(argument) }}
- הכללות:
{% include "another_template.html" %}
- Escaping (בריחה): Tornado מבצע בריחה אוטומטית לישויות HTML כדי למנוע התקפות Cross-Site Scripting (XSS). ניתן לבטל זאת באמצעות
{% raw variable %}
.
פעולות אסינכרוניות
העוצמה של Tornado טמונה ביכולות האסינכרוניות שלו. פעולות אסינכרוניות מאפשרות ליישום שלכם לבצע קלט/פלט לא חוסם, מה שמשפר את הביצועים והסקלביליות. זה שימושי במיוחד למשימות הכוללות המתנה למשאבים חיצוניים, כמו שאילתות למסד נתונים או בקשות רשת.
@tornado.gen.coroutine
:
הדקורטור @tornado.gen.coroutine
מאפשר לכם לכתוב קוד אסינכרוני באמצעות מילת המפתח yield
. זה גורם לקוד אסינכרוני להיראות ולהתנהג יותר כמו קוד סינכרוני, מה שמשפר את הקריאות והתחזוקה.
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'))
בדוגמה זו, http_client.fetch()
היא פעולה אסינכרונית המחזירה Future
. מילת המפתח yield
משעה את ביצוע הקורוטינה עד שה-Future
ייפתר. ברגע שה-Future
נפתר, הקורוטינה מתחדשת וגוף התגובה נכתב ללקוח.
tornado.concurrent.Future
:
אובייקט Future
מייצג את התוצאה של פעולה אסינכרונית שייתכן שעדיין אינה זמינה. ניתן להשתמש באובייקטי Future
כדי לשרשר פעולות אסינכרוניות יחד ולטפל בשגיאות.
tornado.ioloop.IOLoop
:
ה-IOLoop
הוא הלב של המנוע האסינכרוני של Tornado. הוא מנטר מתארי קבצים ושקעים (sockets) לאירועים ושולח אותם למטפלים המתאימים. בדרך כלל אין צורך ליצור אינטראקציה ישירה עם ה-IOLoop
, אך חשוב להבין את תפקידו בטיפול בפעולות אסינכרוניות.
WebSockets
Tornado מספק תמיכה מצוינת ב-WebSockets, המאפשרת תקשורת בזמן אמת בין השרת ללקוחות. WebSockets הם אידיאליים ליישומים הדורשים תקשורת דו-כיוונית עם השהיה נמוכה, כגון יישומי צ'אט, משחקים מקוונים ולוחות מחוונים בזמן אמת.
יצירת מטפל WebSocket:
כדי ליצור מטפל WebSocket, יש לרשת מ-tornado.websocket.WebSocketHandler
ולממש את המתודות הבאות:
open()
: נקראת כאשר נוצר חיבור WebSocket חדש.on_message(message)
: נקראת כאשר מתקבלת הודעה מהלקוח.on_close()
: נקראת כאשר חיבור ה-WebSocket נסגר.
import tornado.websocket
class WebSocketHandler(tornado.websocket.WebSocketHandler):
def open(self):
print("WebSocket opened")
def on_message(self, message):
self.write_message(f"You sent: {message}")
def on_close(self):
print("WebSocket closed")
def check_origin(self, origin):
return True # אפשור חיבורי WebSocket ממקורות שונים
שילוב WebSockets ביישום שלכם:
הוסיפו את מטפל ה-WebSocket לתצורת הניתוב של היישום שלכם:
app = tornado.web.Application([
(r"/ws", WebSocketHandler),
])
מימוש בצד הלקוח:
בצד הלקוח, ניתן להשתמש ב-JavaScript כדי ליצור חיבור WebSocket ולשלוח/לקבל הודעות:
const websocket = new WebSocket("ws://localhost:8888/ws");
websocket.onopen = () => {
console.log("WebSocket connection established");
websocket.send("Hello from the client!");
};
websocket.onmessage = (event) => {
console.log("Received message:", event.data);
};
websocket.onclose = () => {
console.log("WebSocket connection closed");
};
אימות ואבטחה
אבטחה היא היבט קריטי בפיתוח יישומי ווב. Tornado מספק מספר תכונות שיעזרו לכם לאבטח את היישומים שלכם, כולל אימות, הרשאה והגנה מפני פגיעויות ווב נפוצות.
אימות:
אימות הוא תהליך אימות זהותו של משתמש. Tornado מספק תמיכה מובנית במגוון סכימות אימות, כולל:
- אימות מבוסס עוגיות (cookies): אחסון אישורי משתמש בעוגיות.
- אימות צד-שלישי (OAuth): שילוב עם פלטפורמות מדיה חברתית פופולריות כמו גוגל, פייסבוק וטוויטר.
- מפתחות API: שימוש במפתחות API לאימות בקשות API.
הרשאה:
הרשאה היא תהליך קביעה אם למשתמש יש הרשאה לגשת למשאב מסוים. ניתן לממש לוגיקת הרשאה במטפלי הבקשות שלכם כדי להגביל גישה על בסיס תפקידי משתמש או הרשאות.
שיטות עבודה מומלצות לאבטחה:
- הגנה מפני Cross-Site Scripting (XSS): Tornado מבצע בריחה אוטומטית לישויות HTML כדי למנוע התקפות XSS. השתמשו תמיד במתודת
render()
לעיבוד תבניות והימנעו מיצירת HTML ישירות במטפלי הבקשות שלכם. - הגנה מפני Cross-Site Request Forgery (CSRF): אפשרו הגנת CSRF בהגדרות היישום שלכם כדי למנוע התקפות CSRF.
- HTTPS: השתמשו תמיד ב-HTTPS כדי להצפין את התקשורת בין השרת ללקוחות.
- אימות קלט: אמתו את כל קלט המשתמש כדי למנוע התקפות הזרקה ופגיעויות אחרות.
- ביקורות אבטחה סדירות: בצעו ביקורות אבטחה סדירות כדי לזהות ולטפל בפגיעויות פוטנציאליות.
פריסה (Deployment)
פריסת יישום Tornado כוללת מספר שלבים, כולל הגדרת שרת ווב, הגדרת מנהל תהליכים ואופטימיזציה של ביצועים.
שרת ווב:
ניתן לפרוס את Tornado מאחורי שרת ווב כמו Nginx או Apache. שרת הווב פועל כפרוקסי הפוך (reverse proxy), ומעביר בקשות נכנסות ליישום ה-Tornado.
מנהל תהליכים:
ניתן להשתמש במנהל תהליכים כמו Supervisor או systemd כדי לנהל את תהליך ה-Tornado, ולהבטיח שהוא יופעל מחדש באופן אוטומטי אם הוא קורס.
אופטימיזציית ביצועים:
- השתמשו בלולאת אירועים מוכנה לייצור: השתמשו בלולאת אירועים מוכנה לייצור כמו
uvloop
לביצועים משופרים. - אפשרו דחיסת gzip: אפשרו דחיסת gzip כדי להקטין את גודל תגובות ה-HTTP.
- אחסנו קבצים סטטיים במטמון (Cache): אחסנו קבצים סטטיים במטמון כדי להפחית את העומס על השרת.
- נטרו ביצועים: נטרו את ביצועי היישום שלכם באמצעות כלים כמו New Relic או Prometheus.
בינאום (i18n) ולוקליזציה (l10n)
כאשר בונים יישומים לקהל גלובלי, חשוב לקחת בחשבון בינאום (i18n) ולוקליזציה (l10n). i18n הוא תהליך תכנון יישום כך שניתן להתאימו לשפות ואזורים שונים ללא שינויים הנדסיים. l10n הוא תהליך התאמת יישום שעבר בינאום לשפה או אזור ספציפיים על ידי הוספת רכיבים ספציפיים ללוקאל ותרגום טקסט.
Tornado ו-i18n/l10n
ל-Tornado עצמה אין ספריות i18n/l10n מובנות. עם זאת, ניתן לשלב בקלות ספריות פייתון סטנדרטיות כמו `gettext` או פריימוורקים מתוחכמים יותר כמו Babel כדי לטפל ב-i18n/l10n בתוך יישום ה-Tornado שלכם.
דוגמה באמצעות `gettext`:
1. **הגדירו את הלוקאלים שלכם:** צרו ספריות עבור כל שפה שברצונכם לתמוך בה, המכילות קטלוגי הודעות (בדרך כלל קבצי `.mo`).
locales/
en/LC_MESSAGES/messages.mo
fr/LC_MESSAGES/messages.mo
he/LC_MESSAGES/messages.mo
2. **חלצו מחרוזות לתרגום:** השתמשו בכלי כמו `xgettext` כדי לחלץ מחרוזות הניתנות לתרגום מקוד הפייתון שלכם לקובץ `.po` (Portable Object). קובץ זה יכיל את המחרוזות המקוריות ומצייני מיקום לתרגומים.
xgettext -d messages -o locales/messages.po your_tornado_app.py
3. **תרגמו את המחרוזות:** תרגמו את המחרוזות בקבצי ה-`.po` עבור כל שפה.
4. **הידור התרגומים:** הדרו (compile) את קבצי ה-`.po` לקבצי `.mo` (Machine Object) המשמשים את `gettext` בזמן ריצה.
msgfmt locales/he/LC_MESSAGES/messages.po -o locales/he/LC_MESSAGES/messages.mo
5. **שלבו ביישום ה-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:
# טפלו במקרים שהלוקאל אינו נתמך על ידי המערכת
print(f"Locale {self.get_user_locale().code} not supported")
translation = gettext.translation('messages', 'locales', languages=[self.get_user_locale().code])
translation.install()
self._ = translation.gettext
def get_current_user_locale(self):
# לוגיקה לקביעת הלוקאל של המשתמש (למשל, מכותרת Accept-Language, הגדרות משתמש וכו')
# זוהי דוגמה מפושטת - תצטרכו פתרון חזק יותר
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. **שנו את התבניות שלכם:** השתמשו בפונקציה `_()` (המקושרת ל-`gettext.gettext`) כדי לסמן מחרוזות לתרגום בתבניות שלכם.
<h1>{{ _("Welcome to our website!") }}</h1>
<p>{{ _("This is a translated paragraph.") }}</p>
שיקולים חשובים לקהלים גלובליים:
- **קידוד תווים:** השתמשו תמיד בקידוד UTF-8 כדי לתמוך במגוון רחב של תווים.
- **עיצוב תאריך ושעה:** השתמשו בעיצוב תאריך ושעה ספציפי ללוקאל. ניתן להשתמש בפונקציות `strftime` ו-`strptime` של פייתון עם הגדרות לוקאל.
- **עיצוב מספרים:** השתמשו בעיצוב מספרים ספציפי ללוקאל (למשל, מפרידי עשרונים, מפרידי אלפים). מודול `locale` מספק פונקציות לכך.
- **עיצוב מטבע:** השתמשו בעיצוב מטבע ספציפי ללוקאל. שקלו להשתמש בספרייה כמו `Babel` לטיפול מתקדם יותר במטבעות.
- **שפות מימין לשמאל (RTL):** תמכו בשפות RTL כמו ערבית ועברית. זה עשוי לכלול היפוך של פריסת האתר שלכם.
- **איכות התרגום:** השתמשו במתרגמים מקצועיים כדי להבטיח תרגומים מדויקים ומתאימים מבחינה תרבותית. תרגום מכונה יכול להיות נקודת התחלה טובה, אך לעיתים קרובות הוא דורש סקירה אנושית.
- **זיהוי לוקאל משתמש:** משמו זיהוי לוקאל חזק המבוסס על העדפות המשתמש, הגדרות הדפדפן או כתובת ה-IP. ספקו דרך למשתמשים לבחור ידנית את השפה המועדפת עליהם.
- **בדיקות:** בדקו היטב את היישום שלכם עם לוקאלים שונים כדי להבטיח שהכל מוצג כראוי.
נושאים מתקדמים
דפי שגיאה מותאמים אישית:
ניתן להתאים אישית את דפי השגיאה ש-Tornado מציג כאשר מתרחשת שגיאה. זה מאפשר לכם לספק חווית משתמש ידידותית יותר ולכלול מידע לניפוי באגים.
הגדרות מותאמות אישית:
ניתן להגדיר הגדרות מותאמות אישית בתצורת היישום שלכם ולגשת אליהן במטפלי הבקשות. זה שימושי לאחסון פרמטרים ספציפיים ליישום, כגון מחרוזות חיבור למסד נתונים או מפתחות API.
בדיקות:
בדקו היטב את יישומי ה-Tornado שלכם כדי להבטיח שהם פועלים כראוי ובאופן מאובטח. השתמשו בבדיקות יחידה, בדיקות אינטגרציה ובדיקות קצה-לקצה כדי לכסות את כל ההיבטים של היישום שלכם.
סיכום
Tornado הוא פריימוורק ווב עוצמתי ורב-תכליתי המתאים היטב לבניית יישומי ווב סקלביליים ובעלי ביצועים גבוהים. הארכיטקטורה האסינכרונית שלו, התמיכה ב-WebSocket וה-API הקל לשימוש הופכים אותו לבחירה פופולרית בקרב מפתחים ברחבי העולם. על ידי ביצוע ההנחיות והדוגמאות במדריך מקיף זה, תוכלו להתחיל לבנות יישומי Tornado משלכם ולנצל את תכונותיו הרבות.
זכרו לעיין בתיעוד הרשמי של Tornado לקבלת המידע המעודכן ביותר ושיטות העבודה המומלצות. קידוד נעים!