python开发之Tornado

本文详细介绍了Python的Tornado框架,包括其非阻塞特性和高性能特点,阐述了Tornado的基础,如基本步骤、路由系统和模板。此外,还探讨了如何利用Tornado自定义session组件及其改进,以及Tornado作为异步非阻塞Web框架的基本使用和自定义。文章最后讨论了异步非阻塞Web框架的三种类型,并提供了相关参考资料。
摘要由CSDN通过智能技术生成

一、Tornado基础

Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架。我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每一个活动用户都会保持着一个服务器连接。

1. 基本步骤

import tornado.ioloop
import tornado.web
  
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
  
application = tornado.web.Application([
    (r"/index", MainHandler),
])
   
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
  • 第一步:执行脚本,监听 8888 端口。
  • 第二步:浏览器客户端访问 /index --> http://127.0.0.1:8888/index。
  • 第三步:服务器接受请求,并交由对应的类处理该请求。
  • 第四步:类接受到请求之后,根据请求方式(post / get / delete …)的不同调用并执行相应的方法。
  • 第五步:方法返回值的字符串内容发送浏览器。

2. 路由系统

路由系统其实就是 url 和 类 的对应关系,这里不同于其他框架,其他很多框架均是 url 对应 函数,Tornado中每个url对应的是一个类。

import tornado.ioloop
import tornado.web
  
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
  
class StoryHandler(tornado.web.RequestHandler):
    def get(self, story_id):
        self.write("You requested the story " + story_id)
  
class BuyHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("buy.wupeiqi.com/index")
  
application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/story/([0-9]+)", StoryHandler),
])
  
application.add_handlers('buy.wupeiqi.com$', [
    (r'/index',BuyHandler),
])
  
if __name__ == "__main__":
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()

3. 模板

  • Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。
  • Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {% 和 %} 包起来的 例如 {% if len(items) >2 %}。表达语句是使用 { { 和 }} 包起来的,例如 { { items[0] }}。
  • 控制语句和对应的 Python 语句的格式基本完全相同。我们支持 if、for、while 和 try,这些语句逻辑结束的位置需要用 {% end %} 做标记。还通过 extends 和 block 语句实现了模板继承。这些在 template 模块的代码文档中有着详细的描述。

layout.html

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>老男孩</title>
    <link href="{
   {static_url("css/common.css")}}" rel="stylesheet" />
    {
   % block CSS %}{
   % end %}
</head>
<body>
    <div class="pg-header">
    </div>    
    {
   % block RenderBody %}{
   % end %}  
    <script src="{
   {static_url("js/jquery-1.8.2.min.js")}}"></script>
    {
   % block JavaScript %}{
   % end %}
</body>
</html>

index.html

{
   % extends 'layout.html'%}
{
   % block CSS %}
    <link href="{
   {static_url("css/index.css")}}" rel="stylesheet" />
{
   % end %}

{
   % block RenderBody %}
    <h1>Index</h1>
    <ul>
    {
   %  for item in li %}
        <li>{
   {
   item}}</li>
    {
   % end %}
    </ul>
{
   % end %}
{
   % block JavaScript %}    
{
   % end %}

app.py

import tornado.ioloop
import tornado.web
  
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('home/index.html')
  
settings = {
   
    'template_path': 'template',
}
  
application = tornado.web.Application([
    (r"/index", MainHandler),
], **settings)
    
if __name__ == "__main__":
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()

在模板中默认提供了一些函数、字段、类以供模板使用:

escape: 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: for handler.static_url 的別名
xsrf_form_html: handler.xsrf_form_html 的別名

Tornado默认提供的这些功能其实本质上就是 UIMethod 和 UIModule,我们也可以自定义从而实现类似于Django的simple_tag的功能:

1、定义

# uimethods.py
 
def tab(self):
    return 'UIMethod'
# uimodules.py

from tornado.web import UIModule
from tornado import escape

class custom(UIModule):

    def render(self, *args, **kwargs):
        return escape.xhtml_escape('<h1>wupeiqi</h1>')
        #return escape.xhtml_escape('<h1>wupeiqi</h1>')

2、注册

import tornado.ioloop
import tornado.web
from tornado.escape import linkify
import uimodules as md
import uimethods as mt

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,
    'ui_modules': md,
}

application = tornado.web.Application([
    (r"/index", MainHandler),
], **settings)


if __name__ == "__main__":
    application.listen(8009)
    tornado.ioloop.IOLoop.instance().start()

3、使用

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <link href="{
   {static_url("commons.css")}}" rel="stylesheet" />
</head>
<body>
    <h1>hello</h1>
    {
   % module custom(123) %}
    {
   {
    tab() }}
</body>

UIMethod & UIModule

  • UIMethods 认为所有返回的都是非法的,所以在页面显示的是经过转义之后的,比如浏览器页面显示成这样:<h3>老村长</h3>,这个转义是tornado内部做的。
  • 两个办法告诉tornado不要自动帮我转义了:(1)在settings里写"autoescape" : None, (2)在前端写成 {% raw tab(123) %} 。
  • UIModules 不会自动帮我们转义,如果我们想转义,就手动导入from tornado import
    escape,在return里写成 return escape.xhtml_escape(’<h3>老村长</h3>’),转义会转义成 &lt;h3&gt;老村长&lt;/h3&gt; 在浏览器页面显示为 <h3>老村长</h3>。
  • UIMethods只能返回指定内容,UIModules即可以返回指定内容,还可以生成css和js。

Tornado & Django

  • tornado的路由严格遵循设置,设置为(r"^/login", LoginHandler),在浏览器输入网址就是http://127.0.0.1:8000/login ;如果设置为(r"^/login/", LoginHandler),在浏览器就要输入http://127.0.0.1:8000/login/。而对于Django的路由,如果在设置时最后没加/,在浏览器输入时最后加了/,也可以成功。
  • Chrome浏览器会在你输入的网址后面自动补上/,所以如果tornado的路由设置为(r"^/login", LoginHandler),则会报错:WARNING:tornado.access:404 GET /login/ (127.0.0.1) 1.00ms ;而火狐浏览器不会自动在你输入的网址后面补/,所以能够成功执行。Microsoft Edge也会自动在你输入的网址后面补/ 。如果tornado的路由设置为(r"^/login.html", LoginHandler), 就不会报错。

二、利用Tornado自定义session组件

1. 知识预备

class C:
    def f1(self):
        print('C')
        # super(C, self).f1()  # super按照查找顺序执行,C没有父类,深度优先查完变广度优先,找到B类的f1方法
class A(C):
    def f1(self):
        print('A')
        # super(A,self).f1()
        B.f1(self)     # 想在A的f1中直接调用B的f1
class B:
    def f1(self):
        print('B')

class Foo(A,B):
    pass

obj = Foo()
obj.f1()

两种调用f1的方法:


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值