Python中如何使用Tornado
这篇文章给大家分享的是有关Python中如何使用Tornado的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
创新互联是一家成都网站建设、做网站,提供网页设计,网站设计,网站制作,建网站,按需定制,网站开发公司,从2013年创立是互联行业建设者,服务者。以提升客户品牌价值为核心业务,全程参与项目的网站策划设计制作,前端开发,后台程序制作以及后期项目运营并提出专业建议和思路。
Tornado 基本操作
Hello World
经典的 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()
整个过程其实就是在创建一个socket服务端并监听8000端口。当请求到来时,根据请求中的url和请求方式(post、get或put等)来指定相应的类中的方法来处理本次请求。在上述示例中 url 在路由系统匹配到时,则服务器会给浏览器返回 Hello World ,否则返回 404: Not Found(tornado内部定义的值), 即完成一次http请求和响应。
模板引擎
Tornao中的模板语言和django中类似。模板引擎将模板文件载入内存,然后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。
不过还是有区别的。Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {% 和 %} 包起来的。例如 {% if len(items) > 2 %}。表达语句是使用 {{ 和 }} 包起来的,例如 {{ items[0] }} 。
控制语句和对应的 Python 语句的格式基本完全相同。支持 if、for、while 和 try,这些语句逻辑结束的位置需要用 {% end %} 做标记。还通过 extends 和 block 语句实现了模板继承。这些在 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()
前端代码,模板语言的使用:
Hello World
{{ k1 }}
{% if k2 == 'v2' %}k2 == v2
{% else %}}k2 != v2
{% end %}
加载配置
上面的前端代码,最好是统一保存在某个目录里,比如新建个tpl目录来存放。把html文件移过去之后,现在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加载配置信息
POST
先准备好如下的页面,在输入框里填入要搜索的关键字,提交后就跳转到搜索引擎搜索的结果:
后端的代码:
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()
静态文件(图片)
静态文件是给用户直接下载的,所以应该单独存放,并且在配置里注册对应的目录。配置的写法:
settings = { 'template_path': 'tpl', # 模板 'static_path': 'imgs', # 静态文件 }
现在可以根据配置里的名称去创建一个新的文件夹 static 用来存放静态文件。然后放张图片进去。
这里故意不用static作为静态文件文件夹的名称,这里只是注册文件夹,但是前端引用的时候,无论你的静态文件放在那里,都是用 static/文件名称 。
加一个img标签到html里,然后验证一下效果。注意src里用的是static,而不是文件夹真正的名称:
这里前端引用的是必须用static,不过这个名字也是可以自定义的:
settings = { 'template_path': 'tpl', # 模板 'static_path': 'imgs', # 静态文件 'static_url_prefix': '/statics/', # 注意两边都要有斜杠/ }
其他操作
self.request.cookies
: 获取cookiesself.set_cookie()
: 设置cookieself.request.headers
: 获取请求头self.set_header()
: 设置响应头,如果出现同一个响应头,会覆盖self.add_header()
: 设置响应头,如果出现同一个响应头,则追加
Tornado 没有提供 session ,所以要用的话,得另外写。同样的,缓存也没有。
进阶操作
最基本的就是上面那些了,这里再补充一点别的。
自定义UIMethod以及UIModule
这个就是模板引擎里的自定义函数。
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('UI Module TEST
')
注册
写一个完整的服务,这里加上注册的代码。先导入上面的文件,然后分别在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', # 静态文件,这里不重要 '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()
使用
这里只需要看明白前端调用的方法就可以了
UI Method
{{ test1() }}
{{ test2() }}
UI Module
{% module Test() %}
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('UI Module TEST
')
javascript的方法会在body的尾部插入script标签,插入js代码
css的方法则会在head里插入style标签,设置css
files就是直接引入文件,进行设置
embedded就是插入返回的字符串作为设置
CSRF
首先在settings里启用csrf:
settings = { "xsrf_cookies": True, }
在 form 中使用
{{ xsrf_form_html() }} 能够输出完整的input标签,但是直接用回被解析为字符串,带着标签的信息作为字符串显示出来。所以上面用的是 {% raw xsrf_form_html() %} 。
在 Ajax 中使用
Ajax使用时,本质上就是去获取本地的cookie,携带cookie再来发送请求:
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页面:
上传文件
接收上传文件:
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标签实现的伪Ajax的实现,略...
异步非阻塞
异步非阻塞IO,高并发高性能是tornado的特点,所以这小节很重要。但是具体内容也没搞明白,只能尽量先记一些。
首先要引入下面的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()
当发送GET请求时,由于方法被@gen.coroutine装饰且yield 一个Future对象,那么Tornado会等待,等待用户向future对象中放置数据或者发送信号,如果获取到数据或信号之后,就开始执行doing方法。
这里发送请求后,永远也不会返回,就是按上面说的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,则直接执行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加入的回调函数就会执行。
这里最终就是希望 future 调用 set_result ,然后就是执行回调函数。
自定义异步非阻塞Web框架
这节主要是想以源码的方式展示分析tornado是怎么实现异步非阻塞的。代码应该不是超的源码,只是借鉴了思路,做了很多简化。
下面是实现异步非阻塞的代码,主要是 select+socket :
https://www.cnblogs.com/wupeiqi/p/6536518.html
什么场景考虑使用Tornado
复杂的应用还是用django来开发。
如果要开发一个API的功能,或者其他的简单的工具、应用,也不用操作数据库。就可以用tornado或者是其他简单的框架。就不需要用django了。
可以选择的简单的框架还有Flask。
感谢各位的阅读!关于“Python中如何使用Tornado”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
本文标题:Python中如何使用Tornado
转载来于:http://pwwzsj.com/article/pspoji.html