Python cho người Việt

Python cho người Việt

Entries tagged “wsgi”

Lập trình web với Python (7)

written by Nguyễn Thành Nam, on Aug 11, 2011 3:00:00 PM.

Trong bài cuối của loạt bài Lập trình web với Python, chúng ta sẽ bàn đến chuẩn WSGI (Web Server Gateway Interface).

WSGI, khác với HTTP, CGI và FCGI, không phải là chuẩn giao thức liên lạc (communication protocol) mà là chuẩn giao tiếp (standard interface) giữa ứng dụng máy chủ (server) và các khung xương (framework) hay các ứng dụng web (web application). Hình tượng hóa mà nói, WSGI nằm phía trên HTTP/CGI/FCGI và phía dưới ứng dụng thật sự. Lớp WSGI giúp lớp ứng dụng trao đổi với lớp máy chủ theo một cách khả chuyển, tức là một ứng dụng WSGI có thể chạy như nhau trên máy chủ khác nhau như Apache, NGINX, hay Lighttpd, sử dụng các giao thức khác nhau như CGI, FCGI, SCGI, hay AJP. Nói một cách khác, WSGI "che" cách liên lạc qua mạng và tạo điều kiện cho ứng dụng web tập trung vào việc xử lý các vấn đề quan trọng hơn.

Một ứng dụng WSGI là một đối tượng gọi được (callable object). Một đối tượng gọi được có thể là một hàm, một phương thức, hoặc một đối tượng có hàm call. Đối tượng gọi được này phải nhận hai tham số là environstart_response. Tham số environ là một từ điển với các khóa theo chuẩn CGI và một số khóa đặc biệt mà máy chủ WSGI có thể truyền cho ứng dụng. start_response là một đối tượng gọi được do máy chủ WSGI cung cấp cho ứng dụng để ứng dụng bắt đầu việc truyền dữ liệu cho máy chủ WSGI. start_response nhận hai tham số là dòng trạng thái trả lời (status string) và một danh sách bộ-2 (list of 2-tuple) các đầu mục (header), mỗi bộ-2 bao gồm tên và giá trị của đầu mục. Giá trị trả về của ứng dụng WSGI là một bộ khả lặp (iterable) sinh ra nội dung sẽ được máy chủ WSGI truyền lại cho máy chủ HTTP hoặc trình duyệt.

Ví dụ:

def simple_app(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

Đầu tiên, ta thiết lập chuỗi trạng thái là 200 OK, xác định đầu mục Content-typetext/plain rồi gọi start_response với các thông tin như vậy. Giá trị trả về là một danh sách với phần tử duy nhất là chuỗi Hello world!\n. Ta cũng có thể trả về chuỗi Hello world! trực tiếp mà không cần đặt nó vào trong một danh sách vì bản thân một chuỗi cũng là một đối tượng khả lặp. Tuy nhiên, làm như vậy không được khuyến khích vì khi đó máy chủ WSGI sẽ phải làm việc nhiều hơn, lặp qua từng ký tự H, e, l, l, o... thay vì lấy thẳng chuỗi trả lời.

Chúng ta sẽ viết lại ứng dụng đếm số lần truy cập như trong kỳ trước theo dạng một ứng dụng WSGI. Chúng ta sẽ tạo tập tin C:\Program Files\Apache Software Foundation\Apache2.2\fcgi-bin\hello2.py với nội dung như sau:

#!C:\Python26\python.exe
from flup.server import fcgi

class HelloApp(object):

	def __init__(self):
		self.count = 0

	def __call__(self, environ, start_response):
		self.count += 1
		start_response('200 OK', [('Content-type', 'text/plain')])
		return ['Hello WSGI World %d' % self.count]

if __name__ == "__main__":
	webapp = HelloApp()
	fcgi.WSGIServer(webapp, bindAddress=("localhost", 8888)).run()

Thực thi ứng dụng này với lệnh python hello2.py, chạy máy chủ Apache với các thiết lập đã làm trong bài viết kỳ trước, và truy cập vào địa chỉ http://localhost/fcgi-bin/hello.py thì chúng ta sẽ thấy hình như sau:

wsgi1.png

Khi làm tươi trình duyệt thì chúng ta nhận được hình sau:

wsgi2.png

So sánh ứng dụng viết theo WSGI và ứng dụng viết theo các giao thức CGI, hay FCGI ta thấy rõ rằng ứng dụng WSGI không cần quan tâm đến việc dữ liệu sẽ được truyền cho trình duyệt bằng cách nào. Ứng dụng WSGI chỉ quan tâm đến việc tạo ra dữ liệu gì và đẩy chỗ dữ liệu đó cho lớp WSGI bên dưới. Lớp này sẽ tự động thực hiện việc truyền tới trình duyệt theo cách tốt nhất có thể.

Tuy nhiên, ứng dụng WSGI cũng phải biết rõ cách hoạt động của máy chủ WSGI. Ví dụ, một ứng dụng WSGI chạy trên máy chủ WSGI theo mô hình CGI thì sẽ không thể trông chờ đến việc sử dụng lại biến toàn cục vì mỗi yêu cầu được một tiến trình riêng xử lý. Đồng thời ứng dụng WSGI cũng phải đảm bảo rằng các chuỗi trả về phải là chuỗi byte (byte string) và không được sử dụng chuỗi unicode (unicode string). Lý do là vì giao thức HTTP không hiểu unicode. Do đó, tốt nhất là ứng dụng WSGI nên gọi encode trên các chuỗi unicode để chuyển các chuỗi unicode thành các chuỗi byte trước khi đưa xuống cho máy chủ WSGI.

Một điểm hay của giao tiếp WSGI là một ứng dụng WSGI có thể gói (wrap) một ứng dụng WSGI khác bên trong. Điều này cho phép chúng ta tạo ra các ứng dụng WSGI hoạt động như các phần giữa (middleware), hoặc bộ lọc (filter).

Ví dụ:

def simple_app(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

def real_app(environ, start_response):
    r = simple_app(environ, start_response)
    return ['Tag!\n'] + r

Với đoạn mã trên, ứng dụng real_app đã gói ứng dụng simple_app và chèn vào một chuỗi Tag!\n phía trước những gì mà simple_app gửi về. Đây là một cách để tạo nên các ứng dụng web lớn từ việc ghép các ứng dụng web nhỏ lại với nhau.

Chúng ta dừng loạt bài Lập trình web với Python tại đây. Sau 7 bài viết ngắn gọn (nhưng diễn ra trong một khoảng thời gian dài), chúng ta đã xem xét qua việc cài đặt Apache, và Python, rồi các giao thức nền tảng như HTTP, CGI. Từ đó, chúng ta bàn đến các giao thức hiện đại hơn, có một số ưu điểm tốt như FCGI với ví dụ đếm số lần truy cập. Cuối cùng chúng ta dừng lại với một thảo luận ngắn về giao tiếp WSGI, là giao tiếp phổ thông nhất để viết ứng dụng web trong thế giới Python.

Tôi hy vọng sẽ gặp bạn đọc trong các bài viết khác. Để thảo luận về loạt bài này, bạn có thể sử dụng diễn đàn http://vithon.org/forum/Forum/show/7/Ung_dung_mang_web.html.

Vithon nâng cấp sử dụng Gevent

written by vithon, on Aug 1, 2011 8:25:00 AM.

Suốt thời gian qua, nhóm PCNV đã sử dụng chế độ CGI để chạy các ứng dụng web và vẫn đảm bảo được việc truy cập của các bạn quan tâm đến ngôn ngữ Python.

Tuy nhiên, để tránh các vấn đề kỹ thuật có thể phát sinh khi số lượng thành viên tăng lên, cũng như do đòi hỏi của một số tính năng trên diễn đàn, nhóm PCNV đã chuyển hai ứng dụng web là Zine và Vithon Forum qua chạy cùng Gevent, tận dụng chế độ trao đổi không đồng bộ. Việc chuyển đổi này hy vọng sẽ khiến tốc độ truy cập được cải tiến đáng kể.

Nếu các bạn gặp trục trặc trong việc truy cập vào trang PCNV và diễn đàn, thì các bạn hãy thông báo cho chúng tôi theo thông tin liên lạc ở đầu trang.

Giới thiệu phần mềm Vithon Forum

written by vithon, on Jul 1, 2010 6:49:39 PM.

Nhóm Python Cho Người Việt (PCNV) hân hạnh công bố phần mềm Vithon Forum đến với cộng đồng.

Giới thiệu

Phần mềm Vithon Forum (gọi tắt là VF) là một phần mềm tự do, mã mở, miễn phí với chức năng chính là một diễn đàn thảo luận tương tự như các gói phần mềm phpBB, punBB, pyForum.

VF là một ứng dụng web được viết bằng ngôn ngữ Python theo mô hình WSGI. VF có thể được triển khai với các máy chủ hỗ trợ WSGI hay CGI ví dụ như Apache. VF có thể sử dụng nhiều hệ cơ sở dữ liệu quan hệ như SQLite, MySQL, Oracle.

Tính năng

VF có các tính năng nổi trội sau:

Đơn giản
VF chỉ thực hiện một công việc chính đó là lưu trữ và hiển thị các thảo luận của người dùng một cách tiện lợi nhất. VF không mong muốn trở thành một công cụ tích hợp thư điện tử, lịch cá nhân, danh sách công việc, nhắn tin, tán gẫu, v.v…
Nhỏ gọn
Vì chỉ phục vụ một số ít tác vụ cơ bản của một diễn đàn, toàn bộ chương trình VF (trừ các thư viện ngoài) chỉ chiếm khoảng 100 kilobyte dung lượng dĩa.
An toàn
VF được phát triển với các tính năng an ninh được đặt lên hàng đầu. Vì sự đơn giản và tính nhỏ gọn của VF nên chương trình được thiết kế ưu tiên sự an toàn hơn tính năng, và việc kiểm tra mã nguồn được thực hiện thường xuyên nhằm đảm bảo sự ưu tiên đó.
Thuận tiện
VF đề cao việc sử dụng các chuẩn mở như OpenID để việc sử dụng VF trở nên dễ dàng hơn cho người dùng. Bên canh đó, các tính năng thông thường mà người dùng đã quen thuộc ở các gói phần mềm khác cũng có mặt trong VF như BBCode. Tất cả chỉ nhằm một mục đích tạo ra môi trường thảo luận thuận tiện.

Yêu cầu hệ thống

Để triển khai VF, hệ thống sẽ cần một số ứng dụng và mô-đun sau:

  • Python v2.5 trở lên.
  • Mô-đun mako
  • Mô-đun werkzeug
  • Mô-đun sqlalchemy
  • Mô-đun routes
  • Mô-đun repoze.who.plugins.openid
  • Mô-đun repoze.what.plugins.xml
  • Mô-đun postmarkup
  • Mô-đun unidecode
  • Mô-đun zope.interface

Các mô-đun này có thể được cài đặt bằng setuptools (easy_install) hoặc pip.

Cài đặt

Mã nguồn của VF có thể được tải về từ địa chỉ http://bitbucket.org/vithon/vithon-forum.

Giải nén mã nguồn vào một thư mục nào đấy, giả sử như /opt/vithon-forum.

Dựa vào nội dung của tập tin config.py để tạo tập tin siteconfig.py mới, với các dòng lệnh gán giá trị phù hợp cho biến toàn cục. Các biến quan trọng cần thay đổi là COOKIE_SECRET, DATABASE_URL, STATIC_CONTENT_PATH, SESSION_STORAGE_PATH.

Tập tin siteconfig.py có thể có dạng sau:

BOARD_NAME = 'Acme Hideout'
COOKIE_SECRET = 'y@h0O'
DATABASE_URL = 'sqlite:////opt/vithon-forum/db.db'
STATIC_CONTENT_PATH = '/opt/vithon-forum/static'
SESSION_STORAGE_PATH = '/tmp/session'
SESSION_COOKIE_NAME = 'sid'
ENTRIES_PER_PAGE = 10
ORGANIZATION = 'Acme Corp'

Sau đó, chúng ta cần phải khởi tạo cơ sở dữ liệu bằng lệnh initdb.

$ cd /opt/vithon-forum
$ python forum.py initdb

Việc cài đặt đã hoàn tất.

Vận hành

Mặc dù cơ sở dữ liệu đã được khởi tạo khi cài đặt nhưng chúng ta chưa có dữ liệu nào trong cơ sở dữ liệu cả. Do đó, trước khi chạy VF, chúng ta sẽ cần phải tạo một số diễn đàn. Chúng ta sẽ sử dụng lệnh shell để thực hiện việc này.

$ cd /opt/vithon-forum
$ python forum.py shell

Lệnh shell sẽ mở một phiên làm việc tương tác cho phép chúng ta sử dụng Python để tác động đến chương trình VF. Chúng ta sẽ nhập vào đoạn mã Python như sau.

from model import *
f1 = Forum(u'Forum 1', u'Dien giai cho Forum 1')
f11 = Forum(u'Forum 1.1', u'Dien giai cho Forum 1.1', f1)
f12 = Forum(u'Forum 1.2', u'Dien giai cho Forum 1.2', f1)
f2 = Forum(u'Forum 2', u'Dien giai cho Forum 2')
f21 = Forum(u'Forum 2.1', u'Dien giai cho Forum 2.1', f2)
f22 = Forum(u'Forum 2.2', u'Dien giai cho Forum 2.2', f2)
session.add(f1)
session.add(f2)
session.commit()

Các câu lệnh trên tạo ra cấu trúc diễn đàn như sau:

Forum 1
  |
  +-- Forum 1.1
  |
  +-- Forum 1.2

Forum 2
  |
  +-- Forum 2.1
  |
  +-- Forum 2.2

Vì VF không có các tính năng quản lý qua web nên lệnh shell cũng chính là môi trường quản lý chính.

Cuối cùng, để chạy VF, chúng ta sẽ dùng lệnh runserver tương tự như sau:

$ cd /opt/vithon-forum
$ python forum.py runserver -h 127.0.0.1 -p 8080

Khi này, nếu ta mở trình duyệt lên và đi đến trang http://127.0.0.1:8080 thì chúng ta sẽ thấy diễn đàn đã hoạt động.

Triển khai theo mô hình CGI

Chúng ta cũng có thể triển khai VF theo mô hình CGI.

Đầu tiên chúng ta cần chép tập tin forum.cgi vào thư mục chứa các tập tin CGI (ví dụ như /var/www/cgi-bin).

Tiếp đến chúng ta cần sửa các lệnh thiết lập đường dẫn trong tập tin này cho phù hợp.

# Set the path to store python package cache
os.environ['PYTHON_EGG_CACHE'] = '/tmp/.egg'
# Set the path to vithon forum here
sys.path.insert(0, '/opt/vithon-forum')

Nếu như tập tin siteconfig.py nằm ở thư mục khác (ví dụ như trong thư mục /var/www/cgi-bin), thì chúng ta cũng sẽ cần thêm vào các dòng bên dưới. Nếu siteconfig.py nằm chung chỗ với các tập tin khác của VF thì chúng ta không cần các dòng lệnh này.

# Set the path to siteconfig.py here
sys.path.insert(0, '/var/www/cgi-bin')

Và cuối cùng chúng ta chỉ cần cấu hình máy chủ web để sử dụng tập tin forum.cgi như là một ứng dụng CGI. Thông tin về vấn đề này được nói rõ hơn trong tài liệu đi kèm với máy chủ web.