您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關Python中如何使用Tornado的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
經典的 hello world 示例:
import tornado.web # 視圖 class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello World.") # 路由 application = tornado.web.Application([ (r"/", MainHandler), (r"/hello", MainHandler), ]) if __name__ == '__main__': import tornado.ioloop application.listen(8000) tornado.ioloop.IOLoop.instance().start()
整個過程其實就是在創(chuàng)建一個socket服務端并監(jiān)聽8000端口。當請求到來時,根據請求中的url和請求方式(post、get或put等)來指定相應的類中的方法來處理本次請求。在上述示例中 url 在路由系統(tǒng)匹配到時,則服務器會給瀏覽器返回 Hello World ,否則返回 404: Not Found(tornado內部定義的值), 即完成一次http請求和響應。
Tornao中的模板語言和django中類似。模板引擎將模板文件載入內存,然后將數據嵌入其中,最終獲取到一個完整的字符串,再將字符串返回給請求者。
不過還是有區(qū)別的。Tornado 的模板支持“控制語句”和“表達語句”,控制語句是使用 {% 和 %} 包起來的。例如 {% if len(items) > 2 %}。表達語句是使用 {{ 和 }} 包起來的,例如 {{ items[0] }} 。
控制語句和對應的 Python 語句的格式基本完全相同。支持 if、for、while 和 try,這些語句邏輯結束的位置需要用 {% end %} 做標記。還通過 extends 和 block 語句實現(xiàn)了模板繼承。這些在 template 模塊的代碼文檔中有著詳細的描述。在使用模板前需要在setting中設置模板路徑:"template_path" : "tpl"
使用模板引擎的簡單示例,后端代碼:
import tornado.web class IndexHandler(tornado.web.RequestHandler): def get(self): self.render("index.html", k1='v1', k2='v2') # k1和k2是傳給模板引擎處理的內容 application = tornado.web.Application([ (r"/index", IndexHandler), ]) if __name__ == '__main__': import tornado.ioloop application.listen(8000) tornado.ioloop.IOLoop.instance().start()
前端代碼,模板語言的使用:
<body> <h2>Hello World</h2> <h4>{{ k1 }}</h4> {% if k2 == 'v2' %} <h4>k2 == v2</h4> {% else %}} <h3>k2 != v2</h3> {% end %} </body>
上面的前端代碼,最好是統(tǒng)一保存在某個目錄里,比如新建個tpl目錄來存放。把html文件移過去之后,現(xiàn)在render()方法就找不到這個文件了。當然可以改一下參數,把目錄名加進去。不過推薦的做法是把tpl目錄加到配置里去,對上面的代碼進去修改,加入配置信息:
class IndexHandler(tornado.web.RequestHandler): def get(self): self.render("index.html", k1='v1', k2='v2') # 配置就是個key-value的字段 settings = { 'template_path': 'tpl' } application = tornado.web.Application([ (r"/index", IndexHandler), ], **settings) # application加載配置信息
先準備好如下的頁面,在輸入框里填入要搜索的關鍵字,提交后就跳轉到搜索引擎搜索的結果:
<body> <form method="POST" action="/baidu"> <input type="text" name="wd" /> <input type="submit" value="百度一下" /> </form> </body>
后端的代碼:
import tornado.web class SearchHandler(tornado.web.RequestHandler): def get(self): self.render("baidu.html") def post(self): wd = self.get_argument('wd') print(wd) self.redirect('https://www.baidu.com/s?wd=%s' % wd) settings = { 'template_path': 'tpl' } application = tornado.web.Application([ (r"/baidu", SearchHandler), ], **settings) if __name__ == '__main__': import tornado.ioloop application.listen(8000) tornado.ioloop.IOLoop.instance().start()
上面的示例,post請求最后是用redirect()返回的,這個是頁面的跳轉。
獲取提交的參數的方法有這些:
class LoginHandler(tornado.web.RequestHandler): def post(self): # 獲取URL中以GET形式傳遞的數據 self.get_query_argument() self.get_query_arguments() # 獲取請求體中以POST形式傳遞的數據 self.get_body_argument() self.get_body_arguments() # 從上面2個里都嘗試獲取 self.get_argument() self.get_arguments()
靜態(tài)文件是給用戶直接下載的,所以應該單獨存放,并且在配置里注冊對應的目錄。配置的寫法:
settings = { 'template_path': 'tpl', # 模板 'static_path': 'imgs', # 靜態(tài)文件 }
現(xiàn)在可以根據配置里的名稱去創(chuàng)建一個新的文件夾 static 用來存放靜態(tài)文件。然后放張圖片進去。
這里故意不用static作為靜態(tài)文件文件夾的名稱,這里只是注冊文件夾,但是前端引用的時候,無論你的靜態(tài)文件放在那里,都是用 static/文件名稱 。
加一個img標簽到html里,然后驗證一下效果。注意src里用的是static,而不是文件夾真正的名稱:
<img src="static/test.jpg" />
這里前端引用的是必須用static,不過這個名字也是可以自定義的:
settings = { 'template_path': 'tpl', # 模板 'static_path': 'imgs', # 靜態(tài)文件 'static_url_prefix': '/statics/', # 注意兩邊都要有斜杠/ }
self.request.cookies
: 獲取cookiesself.set_cookie()
: 設置cookieself.request.headers
: 獲取請求頭self.set_header()
: 設置響應頭,如果出現(xiàn)同一個響應頭,會覆蓋self.add_header()
: 設置響應頭,如果出現(xiàn)同一個響應頭,則追加
Tornado 沒有提供 session ,所以要用的話,得另外寫。同樣的,緩存也沒有。
最基本的就是上面那些了,這里再補充一點別的。
這個就是模板引擎里的自定義函數。
UIMethod 自定義的是個函數,UIModule 自定義的是個類。
定義
把自定義的函數和自定義的類單獨寫在文件里:
# ui_methods.py def test1(self): # 這里的self不能去掉 return "TEST1" def test2(self): return "TEST2" # ui_module.py from tornado.web import UIModule from tornado import escape class Test(UIModule): def render(self, *args, **kwargs): return escape.xhtml_escape('<h4>UI Module TEST</h4>')
注冊
寫一個完整的服務,這里加上注冊的代碼。先導入上面的文件,然后分別在settings里注冊:
import tornado.web import ui_methods as mt import ui_modules as md class MainHandler(tornado.web.RequestHandler): def get(self): self.render('ui.html') settings = { 'template_path': 'tpl', # 模板 'static_path': 'static', # 靜態(tài)文件,這里不重要 'static_url_prefix': '/statics/', # 注意兩邊都要有斜杠/ 'ui_methods': mt, 'ui_modules': md, } application = tornado.web.Application([ (r"/ui", MainHandler), ], **settings) if __name__ == '__main__': import tornado.ioloop application.listen(8000) tornado.ioloop.IOLoop.instance().start()
使用
這里只需要看明白前端調用的方法就可以了
<body> <h2>UI Method</h2> <p>{{ test1() }}</p> <p>{{ test2() }}</p> <h2>UI Module</h2> {% module Test() %} </body>
UIModule里的方法
render 方法返回的內容就是調用模板的位置顯示的內容:
class Test(UIModule): def javascript_files(self): pass def embedded_javascript(self): pass def css_files(self): pass def embedded_css(self): pass def render(self, *args, **kwargs): return escape.xhtml_escape('<h4>UI Module TEST</h4>')
javascript的方法會在body的尾部插入script標簽,插入js代碼
css的方法則會在head里插入style標簽,設置css
files就是直接引入文件,進行設置
embedded就是插入返回的字符串作為設置
首先在settings里啟用csrf:
settings = { "xsrf_cookies": True, }
在 form 中使用
<form action="/new_message" method="post"> {% raw xsrf_form_html() %} <input type="text" name="message"/> <input type="submit" value="提交"/> </form>
{{ xsrf_form_html() }} 能夠輸出完整的input標簽,但是直接用回被解析為字符串,帶著標簽的信息作為字符串顯示出來。所以上面用的是 {% raw xsrf_form_html() %} 。
在 Ajax 中使用
Ajax使用時,本質上就是去獲取本地的cookie,攜帶cookie再來發(fā)送請求:
function getCookie(name) { var r = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return r ? r[1] : undefined; } jQuery.postJSON = function(url, args, callback) { args._xsrf = getCookie("_xsrf"); $.ajax({url: url, data: $.param(args), dataType: "text", type: "POST", success: function(response) { callback(eval("(" + response + ")")); }}); };
先準備一個form表單上傳文件的html頁面:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>上傳文件</title> </head> <body> <form id="my_form" name="form" action="/index" method="POST" enctype="multipart/form-data" > <input name="fff" id="my_file" type="file" /> <input type="submit" value="提交" /> </form> </body> </html>
接收上傳文件:
import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') def post(self, *args, **kwargs): file_metas = self.request.files["fff"] # print(file_metas) for meta in file_metas: file_name = meta['filename'] with open(file_name,'wb') as up: up.write(meta['body']) settings = { 'template_path': 'template', } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == '__main__': import tornado.ioloop application.listen(8000) tornado.ioloop.IOLoop.instance().start()
上傳文件還可以用Ajax,另外還有借助iframe標簽實現(xiàn)的偽Ajax的實現(xiàn),略...
異步非阻塞IO,高并發(fā)高性能是tornado的特點,所以這小節(jié)很重要。但是具體內容也沒搞明白,只能盡量先記一些。
首先要引入下面的2個模塊:
from tornado import gen from tornado.concurrent import Future class AsyncHandler(tornado.web.RequestHandler): @gen.coroutine def get(self): future = Future() future.add_done_callback(self.doing) yield future def doing(self,*args, **kwargs): self.write('async') self.finish()
當發(fā)送GET請求時,由于方法被@gen.coroutine裝飾且yield 一個Future對象,那么Tornado會等待,等待用戶向future對象中放置數據或者發(fā)送信號,如果獲取到數據或信號之后,就開始執(zhí)行doing方法。
這里發(fā)送請求后,永遠也不會返回,就是按上面說的Tornado一直在等待。等待調用了 future.set_result(result) 這個方法。之后就會調用回調函數,而set_result方法里傳遞進去的參數,可以通過 future.result() 獲取到。大致就是這么的用法,但是沒有個使用示例有點不好理解。
Future類
Future類位于tornado源碼的concurrent模塊中。下面是Future類里的一部分代碼作為分析之用:
class Future(object): def done(self): return self._done def result(self, timeout=None): self._clear_tb_log() if self._result is not None: return self._result if self._exc_info is not None: raise_exc_info(self._exc_info) self._check_done() return self._result def add_done_callback(self, fn): if self._done: fn(self) else: self._callbacks.append(fn) def set_result(self, result): self._result = result self._set_done() def _set_done(self): self._done = True for cb in self._callbacks: try: cb(self) except Exception: app_log.exception('exception calling callback %r for %r', cb, self) self._callbacks = None
Future類重要成員函數:
def done(self) : Future的_result成員是否被設置
def result(self, timeout=None) : 獲取Future對象的結果
def add_done_callback(self, fn) : 添加一個回調函數fn給Future對象。如果這個Future對象已經done,則直接執(zhí)行fn,否則將fn加入到Future類的一個成員列表中保存。
def_set_done(self) : 一個內部函數,主要是遍歷列表,逐個調用列表中的callback函數,也就是前面 add_done_calback 加如來的。
def set_result(self, result) : 給Future對象設置result,并且調用_set_done。也就是說,當Future對象獲得result后,所有add_done_callback加入的回調函數就會執(zhí)行。
這里最終就是希望 future 調用 set_result ,然后就是執(zhí)行回調函數。
這節(jié)主要是想以源碼的方式展示分析tornado是怎么實現(xiàn)異步非阻塞的。代碼應該不是超的源碼,只是借鑒了思路,做了很多簡化。
下面是實現(xiàn)異步非阻塞的代碼,主要是 select+socket :
https://www.cnblogs.com/wupeiqi/p/6536518.html
復雜的應用還是用django來開發(fā)。
如果要開發(fā)一個API的功能,或者其他的簡單的工具、應用,也不用操作數據庫。就可以用tornado或者是其他簡單的框架。就不需要用django了。
可以選擇的簡單的框架還有Flask。
感謝各位的閱讀!關于“Python中如何使用Tornado”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。