zoukankan      html  css  js  c++  java
  • Tornado

    Web框架之Tornado

    Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本。这个 Web 框架看起来有些像web.py 或者 Google 的 webapp,不过为了能有效利用非阻塞式服务器环境,这个 Web 框架还包含了一些相关的有用工具 和优化。

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

    下载安装:

    1
    2
    3
    4
    pip3 install tornado
      
    源码安装
    https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz

    框架使用

    一、快速上手

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
        
    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 ...)的不同调用并执行相应的方法
    • 第五步:方法返回值的字符串内容发送浏览器
     异步非阻塞示例

    二、路由系统

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
        
    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()

      Tornado中原生支持二级域名的路由,如:

    三、模板引擎

    Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。

    Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {% 和 %} 包起来的 例如 {% if len(items) > 2 %}。表达语句是使用 {{ 和 }} 包起来的,例如 {{ items[0] }}

    控制语句和对应的 Python 语句的格式基本完全相同。我们支持 ifforwhile 和 try,这些语句逻辑结束的位置需要用 {% end %} 做标记。还通过 extends 和 block 语句实现了模板继承。这些在 template 模块 的代码文档中有着详细的描述。

    注:在使用模板前需要在setting中设置模板路径:"template_path" : "tpl"

    1、基本使用

     app.py
     index.html
     其他方法

    2、母版

     layout.html
     index.html

    3、导入

     header.html
     index.html

    4、自定义UIMethod以UIModule

    a. 定义

     uimethods.py
     uimodules.py

    b. 注册

     View Code

    c. 使用

     View Code

    四、静态文件

    对于静态文件,可以配置静态文件的目录和前段使用时的前缀,并且Tornaodo还支持静态文件缓存。

     app.py
     index.html

    注:静态文件缓存的实现

     View Code

    五、cookie

    Tornado中可以对cookie进行操作,并且还可以对cookie进行签名以放置伪造。

    1、基本操作

    复制代码
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            if not self.get_cookie("mycookie"):
                self.set_cookie("mycookie", "myvalue")
                self.write("Your cookie was not set yet!")
            else:
                self.write("Your cookie was set!")
    复制代码

    2、加密cookie(签名)

    Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登陆用户的 id 之类的信息,你需要对 cookie 作签名以防止伪造。Tornado 通过 set_secure_cookie 和 get_secure_cookie 方法直接支持了这种功能。 要使用这些方法,你需要在创建应用时提供一个密钥,名字为 cookie_secret。 你可以把它作为一个关键词参数传入应用的设置中:

    复制代码
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            if not self.get_secure_cookie("mycookie"):
                self.set_secure_cookie("mycookie", "myvalue")
                self.write("Your cookie was not set yet!")
            else:
                self.write("Your cookie was set!")
                 
    application = tornado.web.Application([
        (r"/", MainHandler),
    ], cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")
    复制代码
     内部算法

    签名Cookie的本质是:

    写cookie过程:

    • 将值进行base64加密
    • 对除值以外的内容进行签名,哈希算法(无法逆向解析)
    • 拼接 签名 + 加密值

    读cookie过程:

    • 读取 签名 + 加密值
    • 对签名进行验证
    • base64解密,获取值内容

    注:许多API验证机制和安全cookie的实现机制相同。

     基于Cookie实现用户验证-Demo
     基于签名Cookie实现用户验证-Demo

    3、JavaScript操作Cookie

    由于Cookie保存在浏览器端,所以在浏览器端也可以使用JavaScript来操作Cookie。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /*
    设置cookie,指定秒数过期
     */
    function setCookie(name,value,expires){
        var temp = [];
        var current_date = new Date();
        current_date.setSeconds(current_date.getSeconds() + 5);
        document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString();
    }

    对于参数:

    • domain   指定域名下的cookie
    • path       域名下指定url中的cookie
    • secure    https使用

    注:jQuery中也有指定的插件 jQuery Cookie 专门用于操作cookie,猛击这里

    六、CSRF

    Tornado中的夸张请求伪造和Django中的相似,跨站伪造请求(Cross-site request forgery)

     配置
     普通表单
     使用 - AJAX

    注:Ajax使用时,本质上就是去获取本地的cookie,携带cookie再来发送请求

    七、上传文件

    1、Form表单上传

     HTML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
     
    import tornado.ioloop
    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__":
        application.listen(8000)
        tornado.ioloop.IOLoop.instance().start()
     
    Python

     2、AJAX上传

     HTML - XMLHttpRequest
     View Code
     HTML - iframe
     Python
     扩展:基于iframe实现Ajax上传示例

    八、验证码

    验证码原理在于后台自动创建一张带有随机内容的图片,然后将内容通过img标签输出到页面。

    安装图像处理模块:pip3 install pillow

    示例截图:

    复制代码
    class CheckCodeHandler(BaseRequestHandler):
        def get(self, *args, **kwargs):
            stream = io.BytesIO()
            img, code = check_code.create_validate_code()
            img.save(stream, "png")
            self.session["CheckCode"] = code
            self.write(stream.getvalue())
    复制代码

    自定义Web组件

    一、Session

    1、面向对象基础

    面向对象中通过索引的方式访问对象,需要内部实现 __getitem__ 、__delitem__、__setitem__方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
        
    class Foo(object):
        
        def __getitem__(self, key):
            print  '__getitem__',key
        
        def __setitem__(self, key, value):
            print '__setitem__',key,value
        
        def __delitem__(self, key):
            print '__delitem__',key
        
        
        
    obj = Foo()
    result = obj['k1']
    #obj['k2'] = 'wupeiqi'
    #del obj['k1']

    2、Tornado扩展

    Tornado框架中,默认执行Handler的get/post等方法之前默认会执行 initialize方法,所以可以通过自定义的方式使得所有请求在处理前执行操作...

    复制代码
    class BaseHandler(tornado.web.RequestHandler):
       
        def initialize(self):
            self.xxoo = "wupeiqi"
       
       
    class MainHandler(BaseHandler):
       
        def get(self):
            print(self.xxoo)
            self.write('index')
     
    class IndexHandler(BaseHandler):
       
        def get(self):
            print(self.xxoo)
            self.write('index')
    复制代码

    3、session

    session其实就是定义在服务器端用于保存用户回话的容器,其必须依赖cookie才能实现。

     自定义Session

    4、分布式Session

     一致性哈西
     session

    二、表单验证

    在Web程序中往往包含大量的表单验证的工作,如:判断输入是否为空,是否符合规则。

     HTML
     Python

    由于验证规则可以代码重用,所以可以如此定义:

     View Code

     

     
  • 相关阅读:
    UVA-679車的摆放(DFS)
    全排列问题(递归调用)
    STL栈的应用—UVA673
    nefu 84 五指山(扩展欧几里德)
    POJ 1061 青蛙的约会(扩展欧几里德)
    nefu 116 两仪剑法
    nefu 115 斐波那契的整除
    HDU 2099 整除的尾数
    Codeforces Round #339 (Div. 2) B. Gena's Code
    Codeforces Round #339 (Div. 2) A. Link/Cut Tree
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/5869875.html
Copyright © 2011-2022 走看看