1. 程式人生 > 實用技巧 >tornado 基本功能

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':'' }) #模板中聲明瞭變數,檢視必須傳值,如果沒有就設定為空;