这篇文章主要记录Tornado基本知识,以后知识点忘了可做查询用。Tornado大体上可以被分为4个主要部分:
- web框架(包括创建web应用的
RequestHandler
类,还有很多其他支持的类) - HTTP客户端和服务端实现 (HTTPServer、AsyncHTTPClient)
- 异步网络库(IOLoop、IOStream),为HTTP组件提供构建模块,也可以用来实现其他协议
- 携程库(tornado.gen),允许异步代码写的更直接而不用链式回调的方式
基础知识
定义urls,并将urls绑定到处理类:
app = tornado.web.Application(handlers=[(r"/",IndexHandler)])
Application可以接受更多的配置项:settings=dict( template_path = os.path.join(os.path.dirname(__file__),"templates"), static_path = os.path.join(os.path.dirname(__file__),"statics"), debug = False, cookie_secret = base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes), #用来使用get_secure_cookie方法 xsrf_cookies = False, login_url = '/mockServer/login' ) urls = [(r"/",IndexHandler)] application = tornado.web.Application(handlers=urls,**settings)
绑定app(包含各种url信息)到http_server:
http_server = tornado.httpserver.HTTPServer(app)
启动server监听(指定端口):
http_server.listen(options.port)
加入到循环事务中,并启动事务:
tornado.ioloop.IOLoop.instance().start()
处理类IndexHandler继承自tornado.web.RequestHandler,需要覆盖其get或post等方法。写内容到网页可以用: self.write(字符串),或者self.render(模版文件,key1=value1),模版文件中使用来引用对象,value1可以是list等复杂类型
RequestHandler类有读写cookie的方法:
set_cookie()
/get_cookie()
使用更安全的方式:set_secure_cookie()
/get_secure_cookie()
,此时需要在Application的setting中增加如下设置:
cookie_secret = base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)
(set_secure_cookie
中加上httponly=True, secure=True
更加安全)
清理指定cookie:clear_cookie('指定名称')
开启 XSRF 保护:
a) 在Application的setting中增加如下设置:
xsrf_cookies = True
b) 在模板文件中的表单里面加入如下标记:{% raw xsrf_form_html () %}
c) 在ajax中增加标记:
function getCookie(name){ var x = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return x ? x[1]:undefined; } $(document).ready(function(){ $("#login").click(function(){ var user = $("#username").val(); var pwd = $("#password").val(); var pd = {"username":user, "password":pwd, "_xsrf":getCookie("_xsrf")}; $.ajax({ type:"post", url:"/", async:true, data:pd, cache:false, success:function(data){ window.location.href = "/user?user="+data; }, error:function(){ alert("error!"); }, }); }); });
json和python对象互相转换:
tornado.escape.json_encode
(python对象)==>json字符串
tornado.escape.json_decode
(json字符串)==>python对象
它们与json 模块中的 dump()、load()功能相仿。用户认证:
a) 具体的Handler的get方法加装饰器:
@tornado.web.authenticated
b) 可以使用self.current_user
变量获取当前用户
c) a/b中的用法实际都会调用当前Handler类的get_current_user
方法,所以前提是需要重载get_current_user
方法,才可以使用。一般编写BaseHandler(tornado.web.RequestHandler)
基类,里面实现get_current_user
方法的重载,然后其他类继承自BaseHandler类
d) 若当前用户不存在(即get_current_user
返回None时),使用调用装饰器或者current_user
变量的时候,会寻找Application里setting的login_url
指定的路径异步与阻塞:
【异步阻塞】
a) 设置异步函数结束后不断开服务器连接,使用`@tornado.web.asynchronous`装饰器。(原理是设置`_auto_finish`值为False,直到执行到`self.finish()`才关闭连接) b) 使用`tornado.ioloop.IOLoop.instance().add_timeout(time.time() + 17, callback=self.on_response)` 设置超时时间,以及所要执行的回调函数 C) 编写回调函数,并在函数最后加上`self.finish()`调用 class SleepHandler(BaseHandler): @tornado.web.asynchronous def get(self): tornado.ioloop.IOLoop.instance().add_timeout(time.time() + 17, callback=self.on_response) def on_response(self): self.render("sleep.html") self.finish() =======另一种写法========= class SleepHandler(tornado.web.RequestHandler): @tornado.gen.coroutine def get(self): yield tornado.gen.Task(tornado.ioloop.IOLoop.instance().add_timeout, time.time() + 17) #yield tornado.gen.sleep(17) self.render("sleep.html")
【异步非阻塞】
python2.7需要安装concurrent模块:`@tornado.concurrent.run_on_executor` TIMEOUT = 30 MAX_WORKERS = 50 class BaseHandler(tornado.web.RequestHandler): executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)
异步函数编写:
@tornado.gen.coroutine def sleep(self): yield tornado.gen.sleep(10) raise tornado.gen.Return('hello world!')
完整实例:
#coding=utf-8 import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web from tornado.options import define,options define("port",default=8000,help="run on the given port",type=int) class IndexHandler(tornado.web.RequestHandler): def get(self): greeting = self.get_argument('greeting','Hello') #get_argument返回的是unicode编码 self.write(greeting+',world!') if __name__=="__main__": tornado.options.parse_command_line() app = tornado.web.Application(handlers=[(r"/",IndexHandler)]) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
• tornado.httpserver:这个模块就是用来解决 web 服务器的 http 协议问题,它提供了不少属性方法,实现客户端和服务器端的互通。Tornado 的非阻塞、单线程的特点在这个模块中体现。
• tornado.ioloop:这个也非常重要,能够实现非阻塞 socket 循环,不能互通一次就结束呀。
• tornado.options:这是命令行解析模块,也常用到。执行终端help命令时出现的提示。
• tornado.web:这是必不可少的模块,它提供了一个简单的 Web 框架与异步功能,从而使其扩展到大量打开的连接,使其成为理想的长轮询。模版:
1) for循环:
{% for i in key1 %} {{i[0]}} {% end %}
2) 书写python表达式:
使用双括号:7
3) 调试模板:from tornado.template import Template print Template("{{ 'python'[0:2] }}").generate() #输出py
4) 编写python语句:for,if,try,while等,可以多层嵌套
{% 语句 %} .... {% end %}
5) 设置变量:
6) 对变量x不进行html转义:{% raw x %}
7) 常用模板函数:
escape(s):替换字符串 s 中的 &、<、> 为他们对应的 HTML 字符。 url_escape(s):使用 urllib.quote_plus 替换字符串 s 中的字符为 URL 编码形式。 json_encode(val):将 val 编码成 JSON 格式。 squeeze(s):过滤字符串 s,把连续的多个空白字符替换成一个空格。
模板继承:
1) 父模板:
{% block 继承块名称 %} 默认内容 {% end %}
2) 子模板:
{% extends "base.html" %} {% block 继承块名称 %} 更新内容 {% end %}
模板组件:
模板中引入其它模板:
{% module Template("message.html", message=message) %}