tornado 路由、模板语言、session
一:tornado路由系统:
1、面向资源编程:
场景:当我们给别人提供api的时候,往往提供url。比如:电影票api:
1 http://movie.jd.com/book_ticket:预订电影票。 2 http://movie.jd.com/get_ticket:获取电影票。 3 http://movie.jd.com/del_ticket:退电影票。
如果我们给别人提供如上url api的话,那么我们和使用接口方的人需要维护这几个url。相应的成本较高。
因为如上的原因,有人根据url(统一资源定位符)提出设想:
我们是否可以根据用户的请求的method来给用户不同的服务呢?
for example:
1 def get(*arg): 2 pass #查询电影票 3 def post(*arg): 4 passs #订购电影票 5 def put(*arg): 6 pass#退电影票。
根据方法的不同,处理不同的功能。这种提供api方式我们叫做面向资源编程。也叫做restulful(Representational State Transfer缩写,表现层状态转化:http://www.ruanyifeng.com/blog/2011/09/restful)
tornado 天生支持restulful。根据用户的请求的不同,触发不同的函数。以后再给别人提供接口或者在使用别人的接口的时候,需要使用这种面向资源的方式。
2、2级域名,tornado在url划分的时候,比django更加友好,django是在主域名后面接着2级域名比如:http://www.liumeide.com:8888/cmdb/index 配置使用include 进行业务分类url。
而tornado直接使用二级域名来区分不同的业务:http://cmd.liumeide.com:8888/index cmdb服务,http://www.liumeide.com:8888/index 主站服务。http://monitor.liumeide.com:8888/index 监控服务。
京东也是这么区分,只不过京东各个系统是相对独立的。
主站:
团购:
配置:
1 application.add_handlers("cmd.liumeide.com",#重新设置url使用add_handlers方法,第一个参数是2级域名名称,后面是url列表。 2 [ 3 (r"/index", CmdbHandler) 4 ]
完整代码:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import tornado.ioloop 5 import tornado.web 6 7 8 class MainHandler(tornado.web.RequestHandler): 9 def get(self): 10 self.write("mian web") 11 class CmdbHandler(tornado.web.RequestHandler): 12 def get(self): 13 # self.write("Hello, world") 14 self.write('cmdb') 15 setting={ 16 'template_path':'template',#设置模板文件路径。 17 'static_path':'static'#设置静态资源路径 18 } 19 application = tornado.web.Application([ 20 (r"/index", MainHandler), 21 ],**setting) 22 application.add_handlers("cmd.liumeide.com",#重新设置url使用add_handlers方法,第一个参数是2级域名名称,后面是url列表。 23 [ 24 (r"/index", CmdbHandler) 25 ] 26 ) 27 28 if __name__ == "__main__": 29 application.listen(8888) 30 tornado.ioloop.IOLoop.instance().start()
note:
- 他们公用一个setting配置。!!!
效果:
二:模板语言:
在模板语言中,for循环支持break、continue等语法,语法形式:{%break%} 也支持python的一些方法.比如lenth等。
也支持母板和子板,只是结束符是end 而不是 endblock。
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> 5 <title>老男孩</title> 6 <link href="{{static_url("css/common.css")}}" rel="stylesheet" /> 7 {% block CSS %}{% end %} 8 </head> 9 <body> 10 11 <div class="pg-header"> 12 13 </div> 14 15 {% block RenderBody %}{% end %} 16 17 <script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script> 18 19 {% block JavaScript %}{% end %} 20 </body> 21 </html>
子板:
1 {% extends 'layout.html'%} 2 {% block CSS %} 3 <link href="{{static_url("css/index.css")}}" rel="stylesheet" /> 4 {% end %} 5 6 {% block RenderBody %} 7 <h1>Index</h1> 8 9 <ul> 10 {% for item in li %} 11 <li>{{item}}</li> 12 {% end %} 13 </ul> 14 15 {% end %} 16 17 {% block JavaScript %} 18 19 {% end %} 20
导入:也有页面的导入
header.html
1 <div> 2 <ul> 3 <li>1024</li> 4 <li>42区</li> 5 </ul> 6 </div> 7 8 header.html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> 5 <title>老男孩</title> 6 <link href="{{static_url("css/common.css")}}" rel="stylesheet" /> 7 </head> 8 <body> 9 10 <div class="pg-header"> 11 {% include 'header.html' %} 12 </div> 13 14 <script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script> 15 16 </body> 17 </html> 18 19 index.html
自定制功能:uimethod和uimodlues。
对比:
- 2者都可以给前端传递参数,不过method只能传递方法函数,而uimodules传递是类,通过类定义不同的方法,前端调用不方法函数。
- uimodules可以给前端传递js、css等。
uimethod:
首先需要定义个模块比如:co.py. 然后写方法:
1 def f1(self,a): 2 return a
在配置setting中注册:
1 import co 2 setting={ 3 'template_path':'template',#设置模板文件路径。 4 'static_path':'static',#设置静态资源路径 5 'ui_methods':co,#注册 6 }
后台代码:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import tornado.ioloop 5 import tornado.web 6 import co 7 8 class MainHandler(tornado.web.RequestHandler): 9 def get(self): 10 self.render('main.html') 11 setting={ 12 'template_path':'template',#设置模板文件路径。 13 'static_path':'static',#设置静态资源路径 14 'ui_methods':co, 15 } 16 application = tornado.web.Application([ 17 (r"/index", MainHandler), 18 ],**setting) 19 20 if __name__ == "__main__": 21 application.listen(8888) 22 tornado.ioloop.IOLoop.instance().start()
前端页面引用:注意是2个大括号类似于变量的引用。
1 <h1> {{f1(2)}}</h1>
效果:
uimodles:
1、定义模块文件:oc.py
2:写类和方法。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from tornado.web import UIModule 4 from tornado import escape 5 6 class custom(UIModule):#注意需要继承模块。 7 8 def render(self, *args, **kwargs): 9 return '<h1> 2</h1>' 10 def javascript_files(self): 11 return 'http://111.js' 12 def css_files(self): 13 return 'http://222.css'
3:前端注册
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import tornado.ioloop 5 import tornado.web 6 import co 7 import oc 8 class MainHandler(tornado.web.RequestHandler): 9 def get(self): 10 self.render('main.html') 11 setting={ 12 'template_path':'template',#设置模板文件路径。 13 'static_path':'static',#设置静态资源路径 14 'ui_methods':co, 15 'ui_modules':oc, 16 } 17 application = tornado.web.Application([ 18 (r"/index", MainHandler), 19 ],**setting) 20 21 if __name__ == "__main__": 22 application.listen(8888) 23 tornado.ioloop.IOLoop.instance().start()
4:页面引用:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <h1> {{f1(2)}}</h1> 9 {% module custom(22) %}<!--注意页面的引用方式不一样uimodule是需要关键字module 以及百分号和uimethod的不同--> 10 </body> 11 </html>
效果:
三:tornado session
设计思想:
- 服务器端产生随机字符串并写入客户端,下次客户端请求的时候携带这个随机字符串。
- 服务器端需要储存该随机字符串,并额外保存用户其他信息,比如:用户名。
- 客户端每次请求,需要判断客户端是否有已经写入cookie。
- 每次访问,更新cookie过期时间。而不是每次都写入随机字符串。
- session信息可以存储在内存、数据库、redis等。设置过期时间,定期清理,释放磁盘空间。
- 对于伪造的cookie,重新写入客户端。
- 随机字符串可以用time来生成md5写入客户端。
代码实现:
1 #!/usr/bin/env python 2 #-*-coding:utf-8-*- 3 # author:liumeide 4 import hashlib 5 import time 6 Session_Info={} 7 8 def md5(): 9 m = hashlib.md5() 10 m.update(bytes(str(time.time()),encoding='utf-8')) 11 return m.hexdigest() 12 13 class Session: 14 def __init__(self,handler): 15 self.handler=handler 16 def check_se(self): 17 current_time = time.time() 18 ret = self.handler.get_cookie('cookie_str', None) # 自定义cookie key值。下次访问的请求的时候根据这个key来获取cookie的随机字符串。 19 if ret: # 在有效的cookie设置范围内。 20 if ret in Session_Info.keys(): # 合法的cookie 21 cookie_str = ret 22 return True 23 else: # 非法伪造或者过期的cookie。 24 cookie_str = md5() 25 else: # 第一次访问请求设置cookie 26 cookie_str = md5() 27 Session_Info[cookie_str] = {} 28 self.handler('cookie_str', cookie_str, expires=current_time + 200) # 无论你是第一次还是多次请求,cookie都需要重新写入浏览器。需要设置过期时间。 29 30 def __getitem__(self, item):#获取cookie 31 pass 32 def __setitem__(self, key, value):#设置cookie 33 pass 34 def __delitem__(self, key):#删除ookie 35 pass