ไทย

สำรวจเชิงลึกเกี่ยวกับ Tornado เว็บเฟรมเวิร์กและไลบรารีเครือข่ายแบบอะซิงโครนัสของ Python เรียนรู้วิธีสร้างแอปพลิเคชันที่ขยายขนาดได้และมีประสิทธิภาพสูง พร้อมคำอธิบายโดยละเอียด ตัวอย่าง และแนวทางปฏิบัติที่ดีที่สุด

เอกสาร Tornado: คู่มือฉบับสมบูรณ์สำหรับนักพัฒนาทั่วโลก

Tornado คือเว็บเฟรมเวิร์กและไลบรารีเครือข่ายแบบอะซิงโครนัสของ Python ซึ่งเดิมพัฒนาขึ้นที่ FriendFeed เหมาะอย่างยิ่งสำหรับ long-polling, WebSockets และแอปพลิเคชันอื่นๆ ที่ต้องการการเชื่อมต่อที่ยาวนานกับผู้ใช้แต่ละคน Network I/O แบบไม่ปิดกั้น (non-blocking) ทำให้สามารถขยายขนาดได้อย่างมากและเป็นตัวเลือกที่มีประสิทธิภาพสำหรับการสร้างเว็บแอปพลิเคชันที่มีประสิทธิภาพสูง คู่มือฉบับสมบูรณ์นี้จะแนะนำแนวคิดหลักของ Tornado และให้ตัวอย่างที่ใช้งานได้จริงเพื่อให้คุณเริ่มต้นได้

Tornado คืออะไร?

หัวใจหลักของ Tornado คือเว็บเฟรมเวิร์กและไลบรารีเครือข่ายแบบอะซิงโครนัส แตกต่างจากเว็บเฟรมเวิร์กแบบซิงโครนัสทั่วไป Tornado ใช้สถาปัตยกรรมแบบ single-threaded และ event-loop-based ซึ่งหมายความว่าสามารถจัดการการเชื่อมต่อพร้อมกันจำนวนมากได้โดยไม่ต้องใช้เธรดต่อการเชื่อมต่อ ทำให้มีประสิทธิภาพและขยายขนาดได้ดีกว่า

คุณสมบัติที่สำคัญของ Tornado:

การตั้งค่าสภาพแวดล้อม Tornado ของคุณ

ก่อนที่จะเริ่มพัฒนาด้วย Tornado คุณต้องตั้งค่าสภาพแวดล้อมของคุณเสียก่อน นี่คือคำแนะนำทีละขั้นตอน:

  1. ติดตั้ง Python: ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง Python 3.6 หรือสูงกว่า คุณสามารถดาวน์โหลดได้จากเว็บไซต์ทางการของ Python (python.org)
  2. สร้างสภาพแวดล้อมเสมือน (แนะนำ): ใช้ venv หรือ virtualenv เพื่อสร้างสภาพแวดล้อมที่แยกออกมาสำหรับโปรเจกต์ของคุณ:
    python3 -m venv myenv
    source myenv/bin/activate  # บน Linux/macOS
    myenv\Scripts\activate  # บน Windows
  3. ติดตั้ง 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!"

คำอธิบาย:

Request Handlers และ Routing

Request handlers เป็นรากฐานของเว็บแอปพลิเคชัน Tornado โดยจะกำหนดวิธีจัดการกับคำขอ HTTP ที่เข้ามาตาม URL ส่วน Routing จะจับคู่ URL กับ request handler ที่เฉพาะเจาะจง

การกำหนด Request Handlers:

ในการสร้าง request handler ให้สืบทอดคลาส tornado.web.RequestHandler และ implement เมธอด 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}")

Routing:

Routing จะถูกกำหนดค่าเมื่อสร้าง tornado.web.Application คุณต้องระบุรายการของ tuples โดยแต่ละ tuple จะประกอบด้วยรูปแบบ URL และ request handler ที่สอดคล้องกัน

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

รูปแบบ URL (URL Patterns):

รูปแบบ URL คือนิพจน์ปรกติ (regular expressions) คุณสามารถใช้กลุ่มนิพจน์ปรกติเพื่อดึงส่วนต่างๆ ของ URL และส่งผ่านเป็นอาร์กิวเมนต์ไปยังเมธอดของ request handler ได้

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 มี templating engine ที่เรียบง่ายและมีประสิทธิภาพ เทมเพลตใช้เพื่อสร้าง HTML แบบไดนามิก โดยแยกตรรกะการนำเสนอ (presentation logic) ออกจากตรรกะของแอปพลิเคชัน (application logic)

การสร้างเทมเพลต:

เทมเพลตมักจะถูกเก็บไว้ในไฟล์แยกต่างหาก (เช่น 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 }} คือ placeholders ที่จะถูกแทนที่ด้วยค่าจริงเมื่อเทมเพลตถูกเรนเดอร์

การเรนเดอร์เทมเพลต:

หากต้องการเรนเดอร์เทมเพลต ให้ใช้เมธอด render() ใน 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)

ตรวจสอบให้แน่ใจว่าการตั้งค่า template_path ถูกกำหนดค่าอย่างถูกต้องในการตั้งค่าแอปพลิเคชันของคุณ โดยค่าเริ่มต้น Tornado จะมองหาเทมเพลตในไดเรกทอรีชื่อ templates ในไดเรกทอรีเดียวกับไฟล์แอปพลิเคชันของคุณ

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

синтаксис шаблонов (Template Syntax):

เทมเพลตของ Tornado รองรับคุณสมบัติต่างๆ รวมถึง:

การทำงานแบบอะซิงโครนัส (Asynchronous Operations)

จุดแข็งของ Tornado อยู่ที่ความสามารถแบบอะซิงโครนัส การทำงานแบบอะซิงโครนัสช่วยให้แอปพลิเคชันของคุณสามารถทำ I/O แบบไม่ปิดกั้น (non-blocking) ได้ ซึ่งช่วยปรับปรุงประสิทธิภาพและการขยายขนาดได้ดีขึ้น สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับงานที่ต้องรอทรัพยากรภายนอก เช่น การสืบค้นฐานข้อมูลหรือการร้องขอเครือข่าย

@tornado.gen.coroutine:

decorator @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 จะระงับการทำงานของ coroutine จนกว่า Future จะได้รับการแก้ไข เมื่อ Future ได้รับการแก้ไขแล้ว coroutine จะกลับมาทำงานต่อและเนื้อหาการตอบกลับจะถูกเขียนไปยังไคลเอ็นต์

tornado.concurrent.Future:

Future แทนผลลัพธ์ของการทำงานแบบอะซิงโครนัสที่อาจยังไม่พร้อมใช้งาน คุณสามารถใช้วัตถุ Future เพื่อเชื่อมโยงการทำงานแบบอะซิงโครนัสเข้าด้วยกันและจัดการกับข้อผิดพลาด

tornado.ioloop.IOLoop:

IOLoop คือหัวใจของ engine แบบอะซิงโครนัสของ Tornado มันจะตรวจสอบ file descriptors และ sockets สำหรับเหตุการณ์ต่างๆ และส่งต่อไปยัง handlers ที่เหมาะสม โดยปกติคุณไม่จำเป็นต้องโต้ตอบกับ IOLoop โดยตรง แต่สิ่งสำคัญคือต้องเข้าใจบทบาทของมันในการจัดการการทำงานแบบอะซิงโครนัส

WebSockets

Tornado รองรับ WebSockets ได้อย่างยอดเยี่ยม ทำให้สามารถสื่อสารแบบเรียลไทม์ระหว่างเซิร์ฟเวอร์และไคลเอ็นต์ได้ WebSockets เหมาะสำหรับแอปพลิเคชันที่ต้องการการสื่อสารแบบสองทิศทางและมีความหน่วงต่ำ เช่น แอปพลิเคชันแชท เกมออนไลน์ และแดชบอร์ดแบบเรียลไทม์

การสร้าง WebSocket Handler:

ในการสร้าง WebSocket handler ให้สืบทอดคลาส tornado.websocket.WebSocketHandler และ implement เมธอดต่อไปนี้:

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 handler ไปยังการกำหนดค่า routing ของแอปพลิเคชันของคุณ:

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

การ Implement ฝั่งไคลเอ็นต์:

ที่ฝั่งไคลเอ็นต์ คุณสามารถใช้ 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");
};

การยืนยันตัวตนและความปลอดภัย (Authentication and Security)

ความปลอดภัยเป็นสิ่งสำคัญอย่างยิ่งในการพัฒนาเว็บแอปพลิเคชัน Tornado มีคุณสมบัติหลายอย่างที่จะช่วยให้คุณรักษาความปลอดภัยของแอปพลิเคชันของคุณ รวมถึงการยืนยันตัวตน การให้สิทธิ์ และการป้องกันช่องโหว่ทางเว็บที่พบบ่อย

การยืนยันตัวตน (Authentication):

การยืนยันตัวตนคือกระบวนการตรวจสอบตัวตนของผู้ใช้ Tornado รองรับรูปแบบการยืนยันตัวตนต่างๆ ในตัว รวมถึง:

การให้สิทธิ์ (Authorization):

การให้สิทธิ์คือกระบวนการพิจารณาว่าผู้ใช้มีสิทธิ์เข้าถึงทรัพยากรเฉพาะหรือไม่ คุณสามารถ implement ตรรกะการให้สิทธิ์ใน request handlers ของคุณเพื่อจำกัดการเข้าถึงตามบทบาทหรือสิทธิ์ของผู้ใช้

แนวทางปฏิบัติที่ดีที่สุดด้านความปลอดภัย:

การนำไปใช้งาน (Deployment)

การนำแอปพลิเคชัน Tornado ไปใช้งานจริงนั้นมีหลายขั้นตอน รวมถึงการกำหนดค่าเว็บเซิร์ฟเวอร์ การตั้งค่า process manager และการปรับปรุงประสิทธิภาพ

เว็บเซิร์ฟเวอร์ (Web Server):

คุณสามารถนำ Tornado ไปใช้งานหลังเว็บเซิร์ฟเวอร์เช่น Nginx หรือ Apache เว็บเซิร์ฟเวอร์จะทำหน้าที่เป็น reverse proxy โดยส่งต่อคำขอที่เข้ามาไปยังแอปพลิเคชัน Tornado

Process Manager:

Process manager เช่น Supervisor หรือ systemd สามารถใช้เพื่อจัดการกระบวนการของ Tornado เพื่อให้แน่ใจว่ามันจะรีสตาร์ทโดยอัตโนมัติหากเกิดข้อผิดพลาด

การปรับปรุงประสิทธิภาพ (Performance Optimization):

การทำให้เป็นสากล (Internationalization - i18n) และการปรับให้เข้ากับท้องถิ่น (Localization - l10n)

เมื่อสร้างแอปพลิเคชันสำหรับผู้ชมทั่วโลก สิ่งสำคัญคือต้องพิจารณาการทำให้เป็นสากล (i18n) และการปรับให้เข้ากับท้องถิ่น (l10n) i18n คือกระบวนการออกแบบแอปพลิเคชันเพื่อให้สามารถปรับให้เข้ากับภาษาและภูมิภาคต่างๆ ได้โดยไม่ต้องมีการเปลี่ยนแปลงทางวิศวกรรม l10n คือกระบวนการปรับแอปพลิเคชันที่ทำให้เป็นสากลแล้วสำหรับภาษาหรือภูมิภาคเฉพาะโดยการเพิ่มส่วนประกอบเฉพาะสำหรับท้องถิ่นนั้นๆ และแปลข้อความ

Tornado กับ i18n/l10n

Tornado เองไม่ได้มีไลบรารี i18n/l10n ในตัว อย่างไรก็ตาม คุณสามารถผสานรวมไลบรารีมาตรฐานของ Python เช่น `gettext` หรือเฟรมเวิร์กที่ซับซ้อนกว่าอย่าง Babel เพื่อจัดการ i18n/l10n ภายในแอปพลิเคชัน Tornado ของคุณได้อย่างง่ายดาย

ตัวอย่างการใช้ `gettext`:

1. **ตั้งค่า locales ของคุณ:** สร้างไดเรกทอรีสำหรับแต่ละภาษาที่คุณต้องการสนับสนุน โดยมี message catalogs (โดยปกติคือไฟล์ `.mo`) อยู่ภายใน

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

2. **ดึงข้อความที่แปลได้:** ใช้เครื่องมือเช่น `xgettext` เพื่อดึงข้อความที่แปลได้จากโค้ด Python ของคุณไปยังไฟล์ `.po` (Portable Object) ไฟล์นี้จะประกอบด้วยข้อความต้นฉบับและพื้นที่สำหรับคำแปล

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

3. **แปลข้อความ:** แปลข้อความในไฟล์ `.po` สำหรับแต่ละภาษา

4. **คอมไพล์คำแปล:** คอมไพล์ไฟล์ `.po` เป็นไฟล์ `.mo` (Machine Object) ซึ่ง `gettext` จะใช้ในขณะรันไทม์

msgfmt locales/fr/LC_MESSAGES/messages.po -o locales/fr/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:
  # จัดการกรณีที่ระบบไม่รองรับ locale
  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):
  # ตรรกะในการกำหนด locale ของผู้ใช้ (เช่น จากเฮดเดอร์ 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>

ข้อควรพิจารณาที่สำคัญสำหรับผู้ชมทั่วโลก:

หัวข้อขั้นสูง (Advanced Topics)

หน้าข้อผิดพลาดที่กำหนดเอง (Custom Error Pages):

คุณสามารถปรับแต่งหน้าข้อผิดพลาดที่ Tornado แสดงเมื่อเกิดข้อผิดพลาดได้ ซึ่งช่วยให้คุณสามารถมอบประสบการณ์ที่เป็นมิตรต่อผู้ใช้มากขึ้นและรวมข้อมูลการดีบักได้

การตั้งค่าที่กำหนดเอง (Custom Settings):

คุณสามารถกำหนดการตั้งค่าที่กำหนดเองในการกำหนดค่าแอปพลิเคชันของคุณและเข้าถึงได้ใน request handlers ของคุณ ซึ่งมีประโยชน์สำหรับการจัดเก็บพารามิเตอร์เฉพาะของแอปพลิเคชัน เช่น สตริงการเชื่อมต่อฐานข้อมูลหรือ API keys

การทดสอบ (Testing):

ทดสอบแอปพลิเคชัน Tornado ของคุณอย่างละเอียดเพื่อให้แน่ใจว่าทำงานได้อย่างถูกต้องและปลอดภัย ใช้ unit tests, integration tests และ end-to-end tests เพื่อครอบคลุมทุกแง่มุมของแอปพลิเคชันของคุณ

สรุป

Tornado เป็นเว็บเฟรมเวิร์กที่มีประสิทธิภาพและหลากหลาย ซึ่งเหมาะสำหรับการสร้างเว็บแอปพลิเคชันที่ขยายขนาดได้และมีประสิทธิภาพสูง สถาปัตยกรรมแบบอะซิงโครนัส การรองรับ WebSocket และ API ที่ใช้งานง่ายทำให้เป็นตัวเลือกยอดนิยมสำหรับนักพัฒนาทั่วโลก โดยการปฏิบัติตามแนวทางและตัวอย่างในคู่มือฉบับสมบูรณ์นี้ คุณสามารถเริ่มสร้างแอปพลิเคชัน Tornado ของคุณเองและใช้ประโยชน์จากคุณสมบัติมากมายของมันได้

อย่าลืมศึกษาเอกสาร Tornado อย่างเป็นทางการสำหรับข้อมูลล่าสุดและแนวทางปฏิบัติที่ดีที่สุด ขอให้สนุกกับการเขียนโค้ด!