tornado 基本功能
目錄
Tornado的特點
Tornado(龍捲風)和Django一樣是Python中比較主流的web框架,Tornado 和現在的主流 Web 伺服器框架也有著明顯的區別:Tornado自帶socket,並且實現了非同步非阻塞,而且對WebSocket協議天然支援。
相對於其他Python網路框架,它有如下特點:
- 完整的web框架:與Django、Flask等一樣,Tornado也提供URL路由對映、Request上下文、基於模板的頁面渲染技術等開發Web應用的必備工具。
- 是一個高效的網路庫,效能與Twisted、Gevent等底層Python框架想媲美:提供了非同步I/O支援、超時事件處理。這使得Tornado除了可以作為Web應用伺服器框架,還可以用來做爬蟲、遊戲伺服器等後臺應用。
- 提供高效的內部HTTP伺服器:雖然其他框架也提供了內部HTTP伺服器,但它們的HTTP伺服器由於效能原因只能用於測試環境。而Tornado的HTTP伺服器與Tornado非同步呼叫緊密結合,可以之間用於生產環境。
- 完備的websocket支援:WebSocket是HTML5的一種新標準,實現了瀏覽器與伺服器之間的雙向實時通訊。
由於Tornado的上述特點,Tornado常被用作大型站點的介面服務框架,而不像Django那樣著眼於簡歷完整的大型網站。
Tornado的基本組成
Tonado由 路由系統、檢視、模板語言等組成,如果習慣了使用Django你會感覺它功能單薄,但是隻有這樣才能足夠輕量,如果用到什麼功能就自己去GitHub上找現成的外掛,或者自實現;以下將對這些基本元件進行逐一介紹。
Django功能概覽: socket:有 中介軟體:無(使用Python的wsgiref模組) 路由系統:有 檢視函式:有 ORM操作:有 模板語言:有 simple_tag:有 cokies:有 session:有 csrf:有 xss:有 其他:快取、訊號、Form元件、ModelFormm、Admin tornado功能概覽: socket:有(非同步非阻塞、支援WebScoket) 路由系統:有 檢視函式:有 靜態檔案:有 ORM操作:無 模板語言:有 simple_tag:有,uimethod,uimodule cokies:有 session:無 csrf:有 xss:有 其他:無
Django | Tornado | |
---|---|---|
socket | 有 | 有 |
路由系統 | 有 | 有 |
檢視函式 | 有 | 有 |
靜態檔案 | 有 | 有 |
模板語言 | 有 | 有 |
ORM操作 | 有 | 無 |
simple_tag | 有 | 有uimethod,uimodule |
cokies | 有 | 有 |
session | 有 | 無 |
csrf | 有 | 有 |
xss | 有 | 有 |
其他 | 快取、訊號、Form元件、ModelFormm、Admin | 無 |
Tornado的基本功能
安裝:
pip install tornado
基本流程
import tornado.ioloop
import tornado.web
# 注意繼承RequestHandler 而不是redirectHandler
class MainHandler(tornado.web.RequestHandler):
def get(self):
"""get請求"""
self.write("Hello World!")
def make_app():
return tornado.web.Application(
[(r"/index", MainHandler), ] # 路由對映到類
)
def main():
app = make_app() # URL路由對映
app.listen(8888) # 建立1個socket物件,監聽8888埠
tornado.ioloop.IOLoop.instance().start()
# 啟動IOLoop,該函式一直執行且不退出,用於處理完所有客戶端的訪問請求
# 相當於conn, addr=socket.accept()進入監聽狀態
第一步:執行指令碼,監聽 8888 埠
第二步:瀏覽器客戶端訪問 /index --> http://127.0.0.1:8888/index/
第三步:伺服器接受請求,根據URL的訪問對映到RequestHandler的子類,並交由對應的類MainHandler處理該請求
第四步:MainHandler類接受到請求之後,根據請求方式(post / get / delete ...)的不同調用並執行相應的方法
第五步:方法返回值的字串內容傳送瀏覽器
配置
setings={
'template_path':'templates', # 配置模板路徑
'static_path':'static', # 配置靜態檔案存放的路徑
'static_url_prefix':'/static/', # 在模板中引用靜態檔案路徑時使用的別名 注意是模板引用時的別名,必須以/開頭以/結尾
"xsrf_cookies": True, # 使用xsrf認證
'cookie_secret' :'xsseffekrjewkhwy' # cokies加密時使用的鹽
}
# 載入路由和配置
application=tornado.web.Application(
[(r'/login/',LoginHandler) ,
(r'/index/',IndexHandler) ,
], # 引數1 路由系統
**setings # 引數2 配置檔案
)
路由系統
與Django類似,用正則字串進行路由匹配。有兩種:固定字串路徑和引數字串路徑。
動態路由:
app=tornado.web.Application(
[
(r'^/index/$',MainHandler),
(r'^/index/(\d+)$',MainHandler), #url傳參
]
)
域名匹配:
#支援域名匹配 www.xxx.com:8888/index/333333
app.add_handlers('www.xxx.com',[
(r'^/index/$', MainHandler),
(r'^/index/(\d+)$', MainHandler),
])
反向生成url:
app.add_handlers('www.zhanggen.com',[
(r'^/index/$', MainHandler,{},"name1"), #反向生成url
(r'^/index/(\d+)$', MainHandler,{},"name2"),
])
class MainHandler(tornado.web.RequestHandler):
def get(self,*args,**kwargs):
url1=self.application.reverse_url('name1')
# reverse_url 反向解析
url2 = self.application.reverse_url('name2', 666)
print(url1,url2)
self.write('hello word')
檢視 RequestHandler
tornado的檢視才有CBV模式,url匹配成功之後先 檢視執行順序為 initialize 、prepare、get/post/put/delete、finish;
接入點函式:需要子類繼承並定義具體行為的函式在RequestHandler中被稱為接入點函式(Entry Point),例如前面的get()函式就是接入點函式。
RequestHandler.initialize():
該方法被子類重寫,實現RequestHandler子類例項的初始化過程。可以為該函式傳遞引數,引數來源於配置URL對映時的定義。
class ProfileHandler(tornado.web.RequestHandler):
def initialize(self, database):
self.database = database
def get(self):
pass
app = tornado.web.Application([(r'/account',ProfileHandler, dict(database="c:\\example.db"))])
# initialize有引數database,在定義URL對映時以dict方式給出
RequestHandler.prepare():
prepare()方法用於呼叫請求處理(get,post等)方法之前的初始化處理,可以根據實際需求進行重寫。通常可以用prepare()方法做資源初始化操作。
RequestHandler.finish():
finish()方法用於請求處理結束後的一些清理工作,例如可以做清理物件佔用的記憶體或者關閉資料庫連線等。
RequestHandler.get()/post():
每個http action在RequestHandler中都已單獨的函式進行處理,都是以對應的HTTP方法小寫的方式名命。
- RequestHandler.get(self,*args,**kwargs)
- RequestHandler.head(self,*args,**kwargs)
- RequestHandler.post(self,*args,**kwargs)
- RequestHandler.delete(self,*args,**kwargs)
- RequestHandler.patch(self,*args,**kwargs)
- RequestHandler.put(self,*args,**kwargs)
- RequestHandler.options(self,*args,**kwargs)
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def initialize(self): #1
print()
def prepare(self):
pass
def get(self,*args,**kwargs):
self.write('hello word')
def post(self, *args, **kwargs):
pass
def finish(self, chunk=None):
pass
super(self,MainHandler).finish()
請求相關輸入捕獲
輸入捕獲是指在RequestHandler中用於獲取客戶端輸入的工具函式和屬性,比如獲取url中的引數、post提交的引數等。
-
self.get_argument('user'): 獲取GET和POST請求攜帶的引數
-
self.get_arguments('user_list'):獲取GET和POST請求引數列表(如chebox標籤和select多選)
-
self.get_query_argument('user'):獲取GET請求攜帶的引數
-
self.get_query_arguments('user_list'):獲取GET請求引數列表(如chebox標籤和select多選)
-
self.get_body_argument('user'):獲取POST請求攜帶的引數
-
self.get_body_arguments('user_list'):獲取POST請求引數列表(如chebox標籤和select多選)
-
self.request.body.decode('utf-8'):獲取json資料
-
self.get_cookie(name, default=None) : 根據cookie名稱獲取cookie值
-
self.request :返回itornado.httputil.HTTPServerRequest物件例項的甦醒,通過該物件可以獲取關於HTTP請求的一切資訊,
import tornado.web class DetailHandler(tornado.web.RequestHandler): def get(self): remote_ip = self.request.remote_ip # 獲取客戶端的IP地址 host = self.request.host # 獲取請求的主機地址
技巧:在一般情況下 用self.get_argument('user',None)
/self.get_arguments('user',None)
即可,因為它們不管是GET還是POST,都可以用它們來獲取請求攜帶的引數,相當於是一種合集。
注:以上取值方式如果取不到值就會報錯,可以設定取不到值就取None;(例如 self.get_argument('user',None))
輸出響應
輸出響應函式是指一組為客戶端生成處理結果的工具函式,擴充套件url的處理結果。下面列舉常用的三種:
self.write(chunk)
: 一般情況下,用於輸出字串到客戶端。如果是一個字典,則會以JSON格式傳送給客戶端,同時將請求頭中的Content_type設定成 application/json。self.render(template_name, **kwargs)
: 用於響應頁面,用給定的引數渲染模板,可以在本函式中傳入模板檔名稱和模板的引數。self.redirect(url,)
: 重定向頁面。
模板語言
tornado的模板語言和python語法一致。
登入示例:
import tornado.ioloop
import tornado.web
class LoginHandler(tornado.web.RequestHandler):
def get(self):
self.render('login.html')
settings={
'template_path':'templates',#配置模板路徑
'static_path':'static', #配置靜態檔案存放的路徑
'static_url_prefix':'/static/' #在模板中引用靜態檔案路徑時使用的別名 注意是模板引用時的別名
}
app=tornado.web.Application([
(r'/login/',LoginHandler) #引數1 路由系統
],
**settings #引數2 配置檔案
)
if __name__ == '__main__':
app.listen(8888) #建立1個socket物件
tornado.ioloop.IOLoop.instance().start()
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/static/dist/css/bootstrap.css">
<title>Title</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-5 col-md-offset-3">
<form method="post" >
<div class="form-group">
<label for="exampleInputEmail1">使用者名稱</label>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="使用者名稱">
</div>
<div class="form-group">
<label for="exampleInputPassword1">密碼</label>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="密碼">
</div>
<button type="submit" class="btn btn-default">提交</button>
</form>
</div>
</div>
</div>
</body>
</html>
引入靜態檔案
通過別名引入靜態檔案:
<link rel="stylesheet" href="/static/coment.css">
static_url()方式一個如靜態檔案:
<link rel="stylesheet" href='{{static_url("dist/css/bootstrap.css") }}'>
通過static_url()方法引入靜態檔案的好處:
1、使用static_url()可以不用考慮靜態檔案修改之後造成引用失效的情況;
2、還會生成靜態檔案url會有一個v=...的引數,這是tornado根據靜態檔案MD5之後的值,如果後臺的靜態檔案修改,這個值就會變化,前端就會重新向後臺請求靜態檔案,保證頁面實時更新,不引用瀏覽器快取;
上下文
如果模板語言中聲明瞭變數,上下文物件必須對應傳值,如果沒有就設定為空,否則會報錯;
self.render('login.html',**{'erro_msg':'' }) #模板中聲明瞭變數,檢視必須傳值,如果沒有就設定為空;