tornado是python的一個輕量級的web框架,主要特點是非阻塞式的,處理速度快,而且是輕量級的,使用方便。反之Django則是一個重量級的大而全的框架,功能較多,生態較全。
HelloWorld
直接看最簡單的demo:
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
])
if __name__ == "__main__":
application = tornado.web.Application([(r"/", MainHandler)])
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
啓動後(注意,文件名不要用tornado命名),在地址欄輸入localhost:8888/test即可看到輸出:
分析一下這個簡單的demo:
首先,生成一個Apptioncation實例,在構造函數中傳入一個列表類型的參數(由url路徑和處理類組成的元組)。
然後,調用Application的listen方法監聽服務器端口,事實上該方法會先創建一個HTTPServer實例,然後在HTTPServer實例上進行監聽,方法描述如下:
def listen(self, port, address="", **kwargs):
"""Starts an HTTP server for this application on the given port.
This is a convenience alias for creating an `.HTTPServer`
object and calling its listen method. Keyword arguments not
supported by `HTTPServer.listen <.TCPServer.listen>` are passed to the
`.HTTPServer` constructor. For advanced uses
(e.g. multi-process mode), do not use this method; create an
`.HTTPServer` and call its
`.TCPServer.bind`/`.TCPServer.start` methods directly.
Note that after calling this method you still need to call
``IOLoop.current().start()`` to start the server.
Returns the `.HTTPServer` object.
.. versionchanged:: 4.3
Now returns the `.HTTPServer` object.
"""
# import is here rather than top level because HTTPServer
# is not importable on appengine
from tornado.httpserver import HTTPServer
server = HTTPServer(self, **kwargs)
server.listen(port, address)
return server
最後,執行IOLoop類的實例方法 start(),即可啓動服務器。
HelloWorld擴展
# coding: utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import tornado.ioloop
import tornado.web
import logging
from tornado.options import define, options
"""定義全局變量,這裏定義了一個端口"""
define("port", default=8888, help="run on the given port", type=int)
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("hello world")
class IndexHandler(tornado.web.RequestHandler):
def get(self):
greeting = self.get_argument('greeting', 'Hello')
self.write(greeting + ',friendly user!')
if __name__ == "__main__":
logging.basicConfig(stream=sys.stdout, level=logging.INFO,
format='%(asctime)s %(levelno)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
)
logging.info("start server ...")
app = tornado.web.Application(handlers=[(r"/", IndexHandler), (r"/test", MainHandler)])
app.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
這裏添加了兩個路由映射,直接輸入服務器地址加端口ip,則映射到MainHandler,輸出“hello world”。如果繼續加一層子路徑/test,則輸出“Hello,friendly user!”。
如果要使用中文,則必須在文件頭加上:
# coding: utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
重載sys模塊並設置編碼方式爲utf-8。
如果要打印日誌,則需要在主函數裏面加上:
logging.basicConfig(stream=sys.stdout, level=logging.INFO,
format='%(asctime)s %(levelno)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
)
表示在控制檯輸出日誌,格式爲:年月日時分秒 日誌級別 日誌內容。
參數處理
get請求
上面的例子中get請求都沒有參數,如果get請求有參數呢?
定義處理類如下:
class ReverseHandler(tornado.web.RequestHandler):
def get(self, input):
self.write(input[::-1])
該處理類能接收get請求,並反序輸出請求參數。
路由映射如下:
handlers=[(r"/reverse/(\w+)", ReverseHandler), xxx]
\w+匹配1個或多個字母、數字或下劃線。括號的含義是讓Tornado保存匹配括號裏面表達式的字符串,並將其作爲請求方法的一個參數傳遞給RequestHandler類。
啓動服務器,通過地址欄發出get請求:http://localhost:8888/reverse/hello, 會將hello作爲參數,反轉輸出"olleh"。
post請求
對於post請求,通過post方法進行處理。
引入textwrap,並定義handler類如下:
class WrapHandler(tornado.web.RequestHandler):
def post(self):
text = self.get_argument('text')
width = self.get_argument('width', 40)
self.write(textwrap.fill(text, int(width)))
該處理類能接收post請求,並獲取兩個參數,分別是text和width,text未指定值,需要從命令行讀取。最終截取text參數的前40個字符輸出。
路由映射如下:
handlers=[(r"/wrap", WrapHandler), xxx]
post請求可以通過命令行curl xxx -d 指令發出:
curl http://localhost:8888/wrap -d text=Lorem+ipsum+dolor+sit+amet,+consectetuer+adipiscing+elit.
輸出結果如下(Tornado可以解析URLencoded和multipart結構的POST請求參數):
Lorem ipsum dolor sit amet, consectetuer