01: tornado基礎篇javascript
一、 安裝tornadojava
一、pip3安裝
pip3 install tornadopython
二、源碼安裝
https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gzweb
二、tornado概述瀏覽器
一、Tornado 是 FriendFeed 使用的可擴展的非阻塞式 web 服務器及其相關工具的開源版本服務器
二、Tornado 和如今的主流 Web 服務器框架(包括大多數 Python 的框架)有着明顯的區別:它是非阻塞式服務器,並且速度至關快。cookie
三、得利於其 非阻塞的方式和對 epoll 的運用,Tornado 每秒能夠處理數以千計的鏈接
四、咱們開發這個 Web 服務器的主要目的就是爲了處理 FriendFeed 的實時功能 ——在 FriendFeed 的應用裏
每個活動用戶都會保持着一個服務器鏈接。
三、tornado快速上手
一、使用pycharm建立一個普通項目s131415文件夾,並建立文件s131415/app.py
二、在app.py中粘貼下列內容,運行app.py文件
三、在瀏覽器中訪問: http://127.0.0.1:8888/index 便可看到「Hello, world!!」請求內容
import tornado.ioloop import tornado.web #一、 處理訪問/index/的get請求: http://127.0.0.1:8888/index/ class MainHandler(tornado.web.RequestHandler): def get(self): self.write("I am index!!") # self.redirect('http://www.baidu.com') # self.render('index.html',k1='v1') #二、 處理訪問 /login/的post請求和get請求: http://127.0.0.1:8888/login/ class LoginHandler(tornado.web.RequestHandler): def get(self): self.write('login') def post(self,*args,**kwargs): self.write('login post') #三、 配置settings settings = { 'template_path': 'template', # 配置html文件模板位置 'static_path': 'static', # 配置靜態文件路徑(圖片等) 'static_url_prefix': '/static/', # 前端引入靜態文件路徑 } #4 路由系統 application = tornado.web.Application([ (r"/index/", MainHandler), (r"/login/", LoginHandler), ],**settings) #5 啓動這個tornado這個程序 if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
一、無正則匹配url (http://127.0.0.1:8000/index/?nid=1&pid=2)
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): nid = self.get_query_argument('nid') pid = self.get_query_argument('pid') self.write("Hello, world") # http://127.0.0.1:8000/index/?nid=1&pid=2 application = tornado.web.Application([ (r"/index/", MainHandler), ]) if __name__ == "__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start()
二、基於(\d+)正則的url
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self,nid,pid): print(nid,pid) self.write("Hello, world") # http://127.0.0.1:8000/index/1/2/ application = tornado.web.Application([ (r"/index/(\d+)/(\d+)/", MainHandler), # 這種只能傳數字 # (r"/index/(\w+)/(\w+)/", MainHandler), # 這種能夠傳數字、字母、下劃線 ]) if __name__ == "__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start()
三、基於正則分組(?P<nid>\d+),能夠不考慮接收參數順序 (推薦)
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self,nid,pid): print(nid,pid) self.write("Hello, world") # http://127.0.0.1:8000/index/1/2/ application = tornado.web.Application([ (r"/index/(?P<nid>\d+)/(?P<pid>\d+)/", MainHandler), # 這種只能傳數字 ]) if __name__ == "__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start()
一、settings可配置參數
settings = { 'template_path': 'template', #配置html文件模板位置 'static_path': 'static', #配置靜態文件路徑(圖片等) 'static_url_prefix': '/static/', #前端引入靜態文件路徑 'ui_methods': mt, 'ui_modules': md, 'xsrf_cookies':True, 'cookie_secret':'xxx', 'login_url':"/auth/login", 'autoescape':None, 'local':"zh_CN", 'debug':True, }
二、獲取get、post請求
import tornado.ioloop import tornado.web #一、 處理訪問/index/的get請求: http://127.0.0.1:9999/index class MainHandler(tornado.web.RequestHandler): def get(self): self.write("I am index!!") # self.redirect('http://www.baidu.com') # self.render('index.html',k1='v1') #二、 處理訪問 /login/的post請求和get請求: http://127.0.0.1:9999/login class LoginHandler(tornado.web.RequestHandler): def get(self): #2.1 獲取url中以get方式傳遞過來的數據: http://127.0.0.1:9999/login/?username=zhangsan # print(self.get_query_argument('username')) # zhangsan # print(self.get_query_arguments('username')) # ['zhangsan'] # print( self.get_argument('username') ) # get和post兩種請求傳遞的數據都能獲取 self.render('login.html') def post(self,*args,**kwargs): #2.2 獲取請求體中以post傳遞的數據 # print( self.get_body_argument('faver') ) # 僅能獲取單選,多選僅能獲取最後一個 # print( self.get_body_arguments('faver') ) # ['1', '2', '3'] 獲取多選 #2.3 get和post兩種請求傳遞的數據都能獲取 # print( self.get_argument('username') ) #2.4 設置和獲取cookie # self.cookies # self.set_cookie() #2.5 設置和獲取請求頭 # self._headers # self.get_header() self.write('login post') #三、 配置settings settings = { 'template_path': 'template', # 配置html文件模板位置 'static_path': 'static', # 配置靜態文件路徑(圖片等) 'static_url_prefix': '/static/', # 前端引入靜態文件路徑 } #4 路由系統 application = tornado.web.Application([ (r"/index/", MainHandler), (r"/login/", LoginHandler), ],**settings) #5 啓動這個tornado這個程序 if __name__ == "__main__": application.listen(9999) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/base.css"> </head> <body> <form method="POST" action="/login/"> <input type="text" name="username"> <h5 class="c1">多選</h5> 男球:<input type="checkbox" name="faver" value="1" /> 足球:<input type="checkbox" name="faver" value="2" /> 皮球:<input type="checkbox" name="faver" value="3" /> <input type="submit" value="提交"> </form> </body> </html>
.c1{ color: red; }
一、for循環
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render("index.html", username='tom',list_info=[11, 22, 33],user_dic={'username':'zhangsan','age':77}) application = tornado.web.Application([ (r"/index", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>用戶名:{{username}}</h3> {% for item in list_info %} <li>{{item}}</li> {% end %} <p></p> {% for item in user_dic %} <li>{{item}} : {{user_dic[item]}}</li> {% end %} </body> </html>
二、if、in、判斷相等
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render("index.html", list_info=[11, 22, 33],username='tom') application = tornado.web.Application([ (r"/index", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% if 11 in list_info %} true {% else %} false {% end %} {% if username == "tom" %} my name is {{username}} {% else %} not tom {% end %} </body> </html>
一、UIModule與UIMethod比較
1. UIModule: 能夠傳參、能夠生成html、css、js代碼
2. UIMethod: 這個不能傳參數,不能生成css,js等,只能生成html文件
二、UIModule和UIMethod使用舉例
import tornado.ioloop import tornado.web from tornado.escape import linkify import uimodules as md #1.導入uimodules模塊 import uimethods as mt #2.導入uimethods模塊 class MainHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') settings = { 'template_path': 'template', 'static_path': 'static', 'static_url_prefix': '/static/', 'ui_methods': mt, #3.將uimethods模塊註冊到settings中 'ui_modules': md, #4.將uimodules模塊註冊到settings中 } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
from tornado.web import UIModule from tornado import escape # uimodule不只能夠幫生成標籤,還能夠幫添加css,js樣式 class custom(UIModule): # def javascript_files(self): # '''一、生成: <script src="base.js"></script> ''' # return ['base.js','header.js'] # # def embedded_javascript(self): # '''二、生成: <script> alert(123); </script> ''' # return "alert(123);" # # def css_files(self): # '''三、在頭部生成: <link rel="stylesheet" href="base.css">''' # return ['base.css','header.css'] # # def embedded_css(self): # '''四、在頭部style標籤生成: <style> .c1{ color:red; } </style>''' # return ".c1{color:red;}" def render(self, *args, **kwargs): '''五、生成html文件''' return escape.xhtml_escape('<h1>tom</h1>')
def tab(self): return '<h1>tom</h1>'
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>hello</h1> <p>{% module custom(123) %}</p> {{ tab() }} </body> </html>
一、模板繼承使用
1. 在master.html中定義模板: {% block css %} {% endblock %}
2. 在子類中引入要繼承的模板: {% extends 'layout.html' %}
二、模板導入
1. 使用時直接導入便可: {% include "header.html" %}
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render("index.html") settings = { 'template_path':'template', 'static_path':'static', 'static_url_prefix':'/static/', } application = tornado.web.Application([ (r"/index/", MainHandler), ],**settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <title>{% block title %}Default title{% end %}</title> <link rel="stylesheet" href="/static/css/base.css"> {% block css %}{% end %} </head> <body> <div class="c1">這裏是layout.html這個母版中的內容</div> {% block RenderBody %}{% end %} </body> </html>
{% extends 'layout.html'%} {% block css %}<link rel="stylesheet" href="/static/css/index.css">{% end %} {% block RenderBody %} <h3 class="c1">這個RenderBody塊繼承的是header.html這個母版</h3> <div> {% include 'header.html' %} </div> {% end %}
<h3> 這裏是header.html中的內容,須要導入的文件 </h3>
import tornado.ioloop 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"] for meta in file_metas: file_name = meta['filename'] with open(file_name,'wb') as up: print('hahah') up.write(meta['body']) settings = { 'template_path': 'template', } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE 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>
一、tornado.gen.coroutine和tornado.web.asynchronous比較
1. @tornado.web.asynchronous 實現長鏈接,調用self.finish()才結束
2. @tornado.gen.coroutine 這個實現異步
3. 你要想異步,就要保持長鏈接,不然你的handler執行完就本身return了
4. @asynchronous會監聽@gen.coroutine的返回結果(Future),並在@gen.coroutine裝飾的代碼段執行完成後自動調用finish。
5. 從Tornado 3.1版本開始,只使用@gen.coroutine就能夠了。
二、tornado實現異步原理
1. 每一個請求過來就會建立一個socket對象,並yield一個future對象,而後tornado就處理下一個鏈接了
2. tornado內部會以socket對象爲key,future對象爲value加入字典
3. tornado內部調用epoll方法監聽這個全局字典,有socket對象變化就會執行future.set_result('...')
4. 執行future.set_result('...')後就會將future.ready標誌位變成True,而後就會調用callback方法返回內容
注1:yield 一個 Future對象,那麼Tornado會等待,直到執行future.set_result('...')纔會釋放
注2:epoll實質是不斷的輪詢所負責的全部socket,當某個socket有數據到達了,就通知用戶進程
import tornado.ioloop import tornado.web from tornado import gen class IndexHandler(tornado.web.RequestHandler): @gen.coroutine def get(self): self.write('I am index!!') application = tornado.web.Application([ (r"/index/", IndexHandler), ]) if __name__ == "__main__": print('http://127.0.0.1:8888/index/') application.listen(8888) tornado.ioloop.IOLoop.instance().start()
#! /usr/bin/env python # -*- coding: utf-8 -*- import tornado.ioloop import tornado.web from tornado import gen from tornado.concurrent import Future future = None class IndexHandler(tornado.web.RequestHandler): @gen.coroutine def get(self): global future future = Future() future.add_done_callback(self.doing) yield future def doing(self,*args,**kwargs): self.write('async') self.finish() class StopHandler(tornado.web.RequestHandler): def get(self): future.set_result('.......') application = tornado.web.Application([ (r"/index/", IndexHandler), (r"/stop/", StopHandler), ]) if __name__ == "__main__": print('http://127.0.0.1:8888/index/') application.listen(8888) tornado.ioloop.IOLoop.instance().start() ''' http://127.0.0.1:8888/index/ # 只要不返回數據,瀏覽器就不會返回一直等着保持長鏈接 http://127.0.0.1:8888/stop/ # 訪問/stop/是會調用future.set_result()此時 /index/就會返回數據 '''