Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本。这个 Web 框架看起来有些像web.py 或者 Google 的 webapp,不过为了能有效利用非阻塞式服务器环境,这个 Web 框架还包含了一些相关的有用工具 和优化。
Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架。我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每一个活动用户都会保持着一个服务器连接。(关于如何扩容 服务器,以处理数以千计的客户端的连接的问题,请参阅 C10K problem。)
安装
1 pip install tornado 2 源码安装 3 https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz
一、快速上手
1 import tornado.ioloop 2 import tornado.web 3 4 class MainHandler(tornado.web.RequestHandler): 5 def get(self): 6 self.write('hello world') 7 8 application = tornado.web.Application([ 9 (r'/',MainHandler), 10 ]) 11 12 if __name__ == '__main__': 13 application.listen(8888) 14 tornado.ioloop.IOLoop.instance().start()
第一步:执行脚本,监听 8888 端口
第二步:浏览器客户端访问 /index --> http://127.0.0.1:8888/index
第三步:服务器接受请求,并交由对应的类处理该请求
第四步:类接受到请求之后,根据请求方式(post / get / delete ...)的不同调用并执行相应的方法
第五步:方法返回值的字符串内容发送浏览器
二、路由系统
路由系统其实就是 url 和 类 的对应关系,这里不同于其他框架,其他很多框架均是 url 对应 函数,Tornado中每个url对应的是一个类
1 import tornado.ioloop 2 import tornado.web 3 4 class MainHandler(tornado.web.RequestHandler): 5 def get(self): 6 self.write("Hello, world") 7 8 9 class StoryHandler(tornado.web.RequestHandler): 10 def get(self, story_id): 11 self.write("You requested the story " + story_id) 12 13 14 class BuyHandler(tornado.web.RequestHandler): 15 def get(self): 16 self.write("buy.wupeiqi.com/index") 17 18 19 application = tornado.web.Application([ 20 (r"/", MainHandler), 21 (r"/story/([0-9]+)", StoryHandler), 22 ]) 23 24 application.add_handlers('buy.laosiji.com$', [ 25 (r'/index', BuyHandler), 26 ]) 27 28 if __name__ == "__main__": 29 application.listen(8888) 30 tornado.ioloop.IOLoop.instance().start()
三、模板
Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者
1 ##模板引擎渲染原理 2 3 li = [] 4 5 li[0] = """ 6 <!DOCTYPE html> 7 <html lang="en"> 8 <head> 9 <meta charset="UTF-8"> 10 <title>Title</title> 11 </head> 12 <body> 13 <h1>Welcome to Tornado</h1> 14 <form action="/login.html" method="post"> 15 <input type="text" name="username" placeholder="用户名"> 16 <input type="password" name="password" placeholder="用户密码"> 17 <input type="submit" value="提交"> 18 19 """ 20 21 li[1] = "用户名或密码错误" #根据msg,传过来对应值 22 {{ msg }} 23 24 li[2] = """ 25 </form> 26 </body> 27 </html> 28 """ 29 30 结果 = "".join(li)
Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {%
和 %}
包起来的 例如 {% if len(items) > 2 %}
。表达语句是使用 {{
和 }}
包起来的,例如 {{ items[0] }}
。
控制语句和对应的 Python 语句的格式基本完全相同。我们支持 if
、for
、while
和 try
,这些语句逻辑结束的位置需要用 {% end %}
做标记。还通过 extends
和 block
语句实现了模板继承。这些在 template
模块 的代码文档中有着详细的描述。
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <div class="pg-header"> 9 <a href="#">girls</a> 10 </div> 11 {% block RenderBody %}{% end %} 12 </body> 13 </html>
1 {% extends 'layout.html' %} 2 3 {% block RenderBody %} 4 <h1>Index</h1> 5 <ul> 6 {% for item in li %} 7 <li>{{ item }}</li> 8 {% end %} 9 </ul> 10 {% end %}
1 import tornado.ioloop 2 import tornado.web 3 4 5 class MainHandler(tornado.web.RequestHandler): 6 def get(self): 7 self.render('home/index.html',li="girls") 8 9 settings = { 10 'template_path':'views' 11 } 12 13 14 application = tornado.web.Application([ 15 (r"/", MainHandler), 16 ],**settings) 17 18 19 if __name__ == "__main__": 20 application.listen(8888) 21 tornado.ioloop.IOLoop.instance().start()
在模板中默认提供了一些函数、字段、类以供模板使用:
scape
:tornado.escape.xhtml_escape
的別名xhtml_escape
:tornado.escape.xhtml_escape
的別名url_escape
:tornado.escape.url_escape
的別名json_encode
:tornado.escape.json_encode
的別名squeeze
:tornado.escape.squeeze
的別名linkify
:tornado.escape.linkify
的別名datetime
: Python 的datetime
模组handler
: 当前的RequestHandler
对象request
:handler.request
的別名current_user
:handler.current_user
的別名locale
:handler.locale
的別名_
:handler.locale.translate
的別名static_url
: forhandler.static_url
的別名xsrf_form_html
:handler.xsrf_form_html
的別名
Tornado默认提供的这些功能其实本质上就是 UIMethod 和 UIModule,我们也可以自定义从而实现类似于Django的simple_tag的功能:
1、定义
1 def tab(request,val): 2 print(request,val) #(<__main__.MainHandler object at 0x0000000003D15748>, 11) 3 return '<a>UIMethod<a>' #若想显示html格式,需在setting设置autoescape以及模板中机上raw 4 # return '<a>UIMethod<a>' #这样渲染不出来 5 # return 'UIMethod'
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from tornado.web import UIModule 5 from tornado import escape 6 7 class Custom(UIModule): 8 def css_files(self): 9 return "sfs" #引入css静态文件 10 11 def embedded_css(self): 12 return ".c1{display:none}" #嵌入css 13 14 def javascript_files(self): 15 return "js" #引入javascript静态文件 16 17 def embedded_javascript(self): 18 return "function f1(){alert(123);}" #生成javascript 19 20 def render_string(self, path, **kwargs): 21 print(path) 22 return "fsgs" 23 24 def render(self, *args, **kwargs): 25 print(self,args,kwargs) #(<uimodules.Custom object at 0x0000000003D3F4E0>, (22,), {}) 26 return "<h1>UIModule</h1>" #默认不进行转译,直接显示html格式 27 # return escape.xhtml_escape('<h1>UIModule</h1>') ->>进行转译,不显示html格式
2、注册
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import tornado.ioloop 5 import tornado.web 6 import uimodules as md 7 import uimethods as mt 8 9 class MainHandler(tornado.web.RequestHandler): 10 def get(self): 11 self.render('home/index.html',li="girls") 12 13 settings = { 14 'template_path':'views', 15 'static_path':'static', 16 'ui_methods':mt,#UIMethod注册 17 'ui_modules': md, #UIModule注册 18 'autoescape':None,#不将tab返回的字符串进行转译(阻止HTML格式渲染) 19 } 20 21 22 application = tornado.web.Application([ 23 (r"/", MainHandler), 24 ],**settings) 25 26 27 if __name__ == "__main__": 28 application.listen(8888) 29 tornado.ioloop.IOLoop.instance().start()
3、使用
1 {% extends 'layout.html' %} 2 3 {% block RenderBody %} 4 <h1>Index</h1> 5 <ul> 6 {% for item in li %} 7 <li>{{ item }}</li> 8 {% end %} 9 </ul> 10 {{ tab(11) }} 11 {% module Custom(22) %} 12 {% end %}
总结:
1 Tornado 2 1.基本操作 3 -路由系统 4 -url -类(根据method执行方法) 5 -控制器 6 class Foo(xxxx): 7 def get(self): 8 self.render() 9 self.write() 10 self.redirect() 11 self.get_argument() 12 self.get_arguments() 13 self.get_cookie() 14 self.set_cookie() 15 16 self.set_secure_cookie('is_login','true') #加密cookie 17 is_login = self.get_secure_cookie('is_login') #获取加密cookie字符串 18 #加密cookie时配置文件设置 19 settings = { 20 # Exception: You must define the 'cookie_secret' setting in your application to use secure cookies 21 'cookie_secret':'fsgfgdrhrthrthryryty' 22 } 23 24 self.request.files['abc'] #获取提交文件 25 self._headers #获取请求头 26 27 self.request 对象 -》from tornado.httpserver import HTTPRequest #查看 28 29 pass 30 def post(self): 31 pass 32 -模板引擎(更接近python) 33 -基本 34 {{ li[0] }} 35 {% for i in range(10) %} 36 {% end %} 37 -UIMethod 在模板中自定义方法(类似django的simple_tag) 38 -内容 39 -UIModule 在模板中自定义方法(类似django的simple_tag) 40 -内容 41 -CSS JS