zoukankan      html  css  js  c++  java
  • Tornado框架

    Tornado解析

    Tornado是使用Python编写的一个强大的、可扩展的Web服务器。它在处理严峻的网络流量时表现得足够强健,但却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中。

    我们现在所知道的Tornado是基于Bret Taylor和其他人员为FriendFeed所开发的网络服务框架,当FriendFeed被Facebook收购后得以开源。不同于那些最多只能达到10,000个并发连接的传统网络服务器,Tornado在设计之初就考虑到了性能因素,旨在解决C10K问题,这样的设计使得其成为一个拥有非常高性能的框架。此外,它还拥有处理安全性、用户验证、社交网络以及与外部服务(如数据库和网站API)进行异步交互的工具。

    快速入手

      1、安装Tornado

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

      

      2、首个Tornado程序

    #!/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")  # 可以返回字符串
        # self.render("s1.html")  # 这个可以返回html
        # self.redircet("www.baidu.com")  # 跳转到某个url
      
    application = tornado.web.Application([
        (r"/index", MainHandler),
    ])
      
      
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    

    示例:

    # !/usr/bin/env python
    # -*- coding:utf-8 -*-
    import tornado.ioloop
    import tornado.web
    
    
    class LoginHandler(tornado.web.RequestHandler):
    
        def get(self, *args, **kwargs):
            # self.render('login.html', state="")  # 返回HTML页面
            self.render('index.html', k1='123')
    
        def post(self, *args, **kwargs):
            user = self.get_argument('username')
            pwd = self.get_argument('password')
            if user == "alex" and pwd == "123":
                self.redirect("http://www.baidu.com")  # 跳转百度的url
    
            else:
                self.write('登录失败,请重新输入')  # 返回字符串
    
    
    settings = {
        'template_path': 'views',
    }
    
    application = tornado.web.Application([
        # (r"/login", LoginHandler),
        (r"/index", LoginHandler),
    ], **settings)
    
    
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    start.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <form method="post" action="/login">
        <input id="user" type="text" name="username" />
        <input id="pwd" type="password" name="password" />
        <input type="submit" value="登录"  />
    </form>
    
    
    </body>
    </html>
    login.html
    <!DOCTYPE html>
    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>{{k1}}</h1>
    <script>
        alert({{ k1}})
    </script>
    </body>
    </html>
    index.html

    基本上所有的Web框架都是以下的流程(以Tornado为例):  

    准备阶段

      加载配置文件

      加载路由映射  application = tornado.web.Application([(r"/index", MainHandler),])

      创建socket  

    循环阶段

      类似socket Server不断的循环监听文件句柄,当有请求过来的时候,根据用户的请求方法来来判断是什么请求,在通过反射来执行相应的函数或类

    流程:

    第一步:执行脚本,监听 8888 端口
    第二步:浏览器客户端访问 /index  -->  http://127.0.0.1:8888/index
    第三步:服务器接受请求,并交由对应的类处理该请求
    第四步:类接受到请求之后,根据请求方式(post(请求) / get(获取) / delete(删除) / pot(设置))的不同调用并执行相应的方法
    第五步:方法返回值的字符串内容发送浏览器
    

      

      3、application配置

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

    内部在执行的时候执行了两个方法__init__方法和self.add_handlers(".*$", handlers)方法  

    add_handlers默认传输的".*$" 就是www,他内部生成的路由映射的时候相当于(二级域名的方式)下图:

     

     如果匹配的是shuaige他会去"shuaige"里去找对应关系,如果没有匹配默认就去.*,他这个就类似Django中的URL分类

    application = tornado.web.Application([
        (r"/index", MainHandler),
    ])
    
    application.add_handlers("shuaige.com",([
        (r"/index", MainHandler),
    ])
    )
    

      

    路由系统

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

    #!/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 Shuaige(tornado.web.RedirectHandler):
        def get(self):
            self.write("This is shuaige web site,hello!")
    
    application = tornado.web.Application([
        (r"/index", MainHandler),
    ])
    
    application.add_handlers("kongweiqi.com",([
        (r"/index", kongweiqi),
    ])
    )
    
    
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    View Code

    路由系统可以分为几类:

    • 静态路由

    • 动态路由

    • 请求方法路由

    • 二级路由

      1、静态路由

    @root.route('/hello/')
    def index():
        return template('<b>Hello {{name}}</b>!', name="weiqi")
    

    并且可以绑定多个装饰器如代码(当你访问hello的时候回执行下面的函数,当你访问index的时候也会执行下面的index函数) 

    @root.route('/index/')
    @root.route('/hello/')
    def index():
        #return "Hello World"
        return template('<b style="background-color:red">Hello {{name}}</b>!', name="Tim")
    
    root.run(host='localhost', port=8080)
    View Code

      2、动态路由(支持正则)

    @root.route('/wiki/<pagename>')
    def callback(pagename):
        ...
    
    #当请求过来之后@root.route('/wiki/<pagename>') 这个pagename值就会自动把值赋值给def callback(pagename):的参数
    View Code
    @root.route('/wiki/<pagename>')
    def callback(pagename):
        ...
     
    @root.route('/object/<id:int>')
    def callback(id):
        ...
     
    @root.route('/show/<name:re:[a-z]+>')
    def callback(name):
        ...
     
    @root.route('/static/<path:path>')
    def callback(path):
        return static_file(path, root='static')
    正则例子

      3、请求方法路由

    在http访问请求中有很多请求方法比如get、post、delete等

    如果使用了@root.get就表示这个装饰器下的函数只接收get请求!

    @root.route('/hello/', method='POST')
    def index():
        ...
     
    @root.get('/hello/')
    def index():
        ...
     
    @root.post('/hello/')
    def index():
        ...
     
    @root.put('/hello/')
    def index():
        ...
     
    @root.delete('/hello/')
    def index():
        ...
    View Code

      4、二级路由  

    多个APP把不同app下的请求转发到不同的app下面进行处理

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from bottle import template, Bottle
    from bottle import static_file
    root = Bottle()
     
    @root.route('/hello/')
    def index():
        return template('<b>Root {{name}}</b>!', name="Alex")
     
    from framwork_bottle import app01
    from framwork_bottle import app02
     
    root.mount('app01', app01.app01)
    root.mount('app02', app02.app02)
     
    root.run(host='localhost', port=8888)
    indexpy
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from bottle import template, Bottle
    
    app01 = Bottle()
    
    @app01.route('/hello/', method='GET')
    def index():
        return template('<b>App01</b>!'
    app01
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from bottle import template, Bottle
    
    app02 = Bottle()
    
    
    @app02.route('/hello/', method='GET')
    def index():
        return template('<b>App02</b>!')
    app02

    模板引擎

      1、解析

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

    Tornado 的模板支持“控制语句”和“表达语句”,

    控制语句是使用 {% 和 %} 包起来的 例如 {% if len(items) > 2 %};

    表达语句是使用 {{ 和 }} 包起来的,例如 {{ items[0] }};

    控制语句和对应的 Python 语句的格式基本完全相同。我们支持 ifforwhile 和 try

    这些语句逻辑结束的位置需要用 {% end %} 做标记。还通过 extends 和 block 语句实现了模板继承。这些在 template 模块 的代码文档中有着详细的描述。

      2、目录结构

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
      
    import tornado.ioloop
    import tornado.web
      
      
    class MainHandler(tornado.web.RequestHandler):
        def get(self):  # 用get 的方式接受
            self.render('home/index.html')  # 可以返回html
            #self.write("Hello world")  # 可以返回字符串
        
        def post(self, *args, **kwargs):  # 用post方式接受
            name = self.get_argument('xxx')
            print(name)
            self.render('index.html')
     
    # 模板路径的配置 
    settings = {
        'template_path': 'template',    # 配置文件路径,设置完可以把HTML文件放置template
        'static_path': 'static',        # 静态文件的配置
    #     'static_url_prefix':'/sss/'   # 静态文件的前缀,在静态文件夹前面加上这个前缀 
        'cookie_secret': "asdasd",      # cookie生成秘钥时候需提前生成随机字符串,需要在这里进行渲染
        'xsrf_cokkies':True,            # 允许CSRF使用
    }
      
      # 路由系统
    application = tornado.web.Application([
        (r"/index", MainHandler),  # 匹配url和类
    ], **settings)  # 接受配置
      
      
    if __name__ == "__main__":
        application.listen(80)
        tornado.ioloop.IOLoop.instance().start()
    主文件index.py
    <!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>
    
    layout.html
    layout.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 %}
    
    index.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 %}
    for循环

      3、语法

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1>1、单值</h1>
          {{name}}
        #应用后端返回的数据
    
        <h1>2、单行Python代码</h1>
            % s1 = "hello"
            {{ s1 }}
        #'%s1 这里设置一个变量,我们可以在html调用和python类似'
    
        <h1>3、Python代码块</h1>
        <%
            # python块代码
            name = name.title().strip()
            if name == "shuaige":
                name="luotianshuai"
        %>
    
        <h1>4、Python、Html混合</h1>
    
        % if True:
            <span>{{name}}</span>
        % end
        <ul>
          % for item in name:
            <li>{{item}}</li>
          % end
        </ul>
    
    </body>
    </html>
    View Code

      4、函数

     include(sub_template, **variables)

    # 导入其他模板文件
     
    % include('header.tpl', title='Page Title')
    Page Content
    % include('footer.tpl')
    

    rebase(name, **variables)

    <html>
    <head>
      <title>{{title or 'No title'}}</title>
    </head>
    <body>
      {{!base}}
    </body>
    </html>
    

    导入母版

    % rebase('base.tpl', title='Page Title')
    <p>Page Content ...</p>
    
    defined(name) #检查当前变量是否已经被定义,已定义True,未定义False
    get(name, default=None) #获取某个变量的值,不存在时可设置默认值
    setdefault(name, default) #如果变量不存在时,为变量设置默认值

    母版继承

    ①相当于python的字符串格式化一样,先定义一个占位符

    <!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>
    layout.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 %}
    index.html

    导入内容

    <div>
        <ul>
            <li>帅</li>
            <li>很帅</li>
            <li>非常帅</li>
        </ul>
    </div>
    content.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" />
    </head>
    <body>
    
        <div class="pg-header">
            {% include 'header.html' %}
        </div>
        
        <script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script>
        
    </body>
    </html>
    index.html

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

    • escapetornado.escape.xhtml_escape 的別名

    • xhtml_escapetornado.escape.xhtml_escape 的別名

    • url_escapetornado.escape.url_escape 的別名

    • json_encodetornado.escape.json_encode 的別名

    • squeezetornado.escape.squeeze 的別名

    • linkifytornado.escape.linkify 的別名

    • datetime: Python 的 datetime 模组

    • handler: 当前的 RequestHandler 对象

    • requesthandler.request 的別名

    • current_userhandler.current_user 的別名

    • localehandler.locale 的別名

    • _handler.locale.translate 的別名

    • static_url: for handler.static_url 的別名

    • xsrf_form_htmlhandler.xsrf_form_html 的別名

      5、自定义模板

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

     1、定义

    def tab(self):
        return 'UIMethod'
    uimethods.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    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>')
    uimodules.py

    2、注册

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    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()
    main.py

    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>
    index.html

      6、 公共组件

    由于Web框架就是用来【接收用户请求】-> 【处理用户请求】-> 【响应相关内容】,对于具体如何处理用户请求,开发人员根据用户请求来进行处理,而对于接收用户请求和相应相关的内容均交给框架本身来处理,其处理完成之后将产出交给开发人员和用户。

    【接收用户请求】

    当框架接收到用户请求之后,将请求信息封装在Bottle的request中,以供开发人员使用

    【响应相关内容】

    当开发人员的代码处理完用户请求之后,会将其执行内容相应给用户,相应的内容会封装在Bottle的response中,然后再由框架将内容返回给用户

    所以,公共组件本质其实就是为开发人员提供接口,使其能够获取用户信息并配置响应内容。

    request.headers
    #请求头信息,可以通过请求头信息来获取相关客户端的信息
     
    request.query
    #get请求信息,如果用户访问时这样的:http://127.0.0.1:8000/?page=123就必须使用request.query  使用GET方法是无法取到信息的
     
    request.forms
    #post请求信息
     
    request.files
    #上传文件信息
     
    request.params
    #get和post请求信息,他是GET和POST的总和,其实他内部调用了request.get request.forms
     
    request.GET
    #get请求信息
     
    request.POST
    #post和上传信息,上传文件信息,和post信息
     
    request.cookies
    #cookie信息
         
    request.environ
    #环境相关相关,如果上面的这些请求信息没有满足你的需求,就在这里找!
    View Code

    实用功能

      1、静态文件

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

    静态文件缓存:

    <link href="{{static_url('css/index.css')}}" rel="stylesheet" />
    """
    在Tornado中写成变量形式的主要是为了以后扩展方便,还有一个缓存的功能
    """
    

    原理:

    拿一个静态文件来说:/static/commons.js如果用Tornado封装后,类似于给他加了一个版本号/static/commons.js?v=sldkfjsldf123

    当客户端访问过来的时候会携带这个值,如果发现没变客户端缓存的静态文件直接渲染就行了,不必再在服务器上下载一下静态文件了。

    #!/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')
    
    settings = {
        'template_path': 'template',
        'static_path': 'static',
        'static_url_prefix': '/static/',
    }
    
    application = tornado.web.Application([
        (r"/index", MainHandler),
    ], **settings)
    
    
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    main.py
    <!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>
    </body>
    </html>
    index.html

    Tornado静态文件实现缓存  

     def get_content_version(cls, abspath):
            """Returns a version string for the resource at the given path.
    
            This class method may be overridden by subclasses.  The
            default implementation is a hash of the file's contents.
    
            .. versionadded:: 3.1
            """
            data = cls.get_content(abspath)
            hasher = hashlib.md5()
            if isinstance(data, bytes):
                hasher.update(data)
            else:
                for chunk in data:
                    hasher.update(chunk)
            return hasher.hexdigest()
    静态文件缓存源码

      2、xss

    跨站脚本攻击

    恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的特殊目的。

    class IndexHandler(tornado.web.RequestHandler):
        def get(self, *args, **kwargs):
            jump = '''<input type="text"><a onclick = "Jump('%s',this);">GO</a>'''%('/index/')
            script = '''
                <script>
                    function Jump(baseUrl,ths){
                        var val = ths.previousElementSibling.value;
                        if (val.trim().length > 0){
                            location.href = baseUrl + val;
                        }
                    }
                </script>
            '''
            self.render('index.html',jump=jump,script=script)  #传入两个前端代码的字符串
    start.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            .pager a{
                display: inline-block;
                padding: 5px;
                margin: 3px;
                background-color: #00a2ca;
            }
            .pager a.active{
                background-color: #0f0f0f;
                color: white;
            }
        </style>
    </head>
    <body>
        <div class="pager">
            {% raw jump %}
            {% raw script%}
        </div>
    </body>
    </html>    
    index.py

      3、CSRF跨站请求伪造

    跨站伪造请求(Cross-site request forgery)

    settings = {
        "xsrf_cookies": True,
    }
    application = tornado.web.Application([
        (r"/", MainHandler),
        (r"/login", LoginHandler),
    ], **settings)
    配置
    <form action="/new_message" method="post">
      {{ xsrf_form_html() }}
      <input type="text" name="message"/>
      <input type="submit" value="Post"/>
    </form>
    普通表单使用
    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 + ")"));
        }});
    };
    
    Ajax使用
    ajax

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

     Tornado 有内建的 XSRF 的防范机制,要使用此机制,你需要在应用配置中加上 xsrf_cookies

    设定:xsrf_cookies=True,再来写一段代码,来表示一下:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import tornado.web
    import tornado.ioloop
    
    class CsrfHandler(tornado.web.RequestHandler):
    
        def get(self, *args, **kwargs):
            self.render('csrf.html')
    
        def post(self, *args, **kwargs):
            self.write('张岩林已经收到客户端发的请求伪造')
    
    
    settings = {
        'template_path':'views',
        'static_path':'statics',
        'xsrf_cokkies':True,        # 重点在这里,往这里看
    }
    
    application = tornado.web.Application([
        (r'/csrf',CsrfHandler)
    ],**settings)
    
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    start.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/csrf" method="post">
            {% raw xsrf_form_html() %}
            <p><input name="user" type="text" placeholder="用户"/></p>
            <p><input name='pwd' type="text" placeholder="密码"/></p>
            <input type="submit" value="Submit" />
            <input type="button" value="Ajax CSRF" onclick="SubmitCsrf();" />
        </form>
        
        <script src="/statics/jquery-1.12.4.js"></script>
        <script type="text/javascript">
    
            function ChangeCode() {
                var code = document.getElementById('imgCode');
                code.src += '?';
            }
            function getCookie(name) {
                var r = document.cookie.match("\b" + name + "=([^;]*)\b");
                return r ? r[1] : undefined;
            }
    
            function SubmitCsrf() {
                var nid = getCookie('_xsrf');
                $.post({
                    url: '/csrf',
                    data: {'k1': 'v1',"_xsrf": nid},
                    success: function (callback) {
                        // Ajax请求发送成功有,自动执行
                        // callback,服务器write的数据 callback=“csrf.post”
                        console.log(callback);
                    }
                });
            }
        </script>
    </body>
    </html>
    csrf.py

    在form验证里面生成了一段类似于自己的身份标识一样,携带着这个标识来访问网页。

      4、Cookie

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

    a、基本操作

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
       
    import tornado.ioloop
    import tornado.web
       
       
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            print(self.cookies)              # 获取所有的cookie
            self.set_cookie('k1','v1')       # 设置cookie
            print(self.get_cookie('k1'))     # 获取指定的cookie
            self.write("Hello, world")
       
    application = tornado.web.Application([
        (r"/index", MainHandler),
    ])
       
       
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()

    b、签名

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

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
       
    import tornado.ioloop
    import tornado.web
        
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
             if not self.get_secure_cookie("mycookie"):             # 获取带签名的cookie
                 self.set_secure_cookie("mycookie", "myvalue")      # 设置带签名的cookie
                 self.write("Your cookie was not set yet!")
             else:
                 self.write("Your cookie was set!")
    application = tornado.web.Application([
        (r"/index", MainHandler),
    ])
       
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()

    签名Cookie的本质是:

    写cookie过程:

    • 将值进行base64加密

    • 对除值以外的内容进行签名,哈希算法(无法逆向解析)

    • 拼接 签名 + 加密值

    读cookie过程:

    • 读取 签名 + 加密值

    • 对签名进行验证

    • base64解密,获取值内容

    c、自定义session

    用cookie做简单的自定义用户验证,下面会写一个绝对牛逼的自定义session用户验证

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
     
    import tornado.ioloop
    import tornado.web
     
    class BaseHandler(tornado.web.RequestHandler):
     
        def get_current_user(self):
            return self.get_secure_cookie("login_user")
     
    class MainHandler(BaseHandler):
     
        @tornado.web.authenticated
        def get(self):
            login_user = self.current_user
            self.write(login_user)
     
    class LoginHandler(tornado.web.RequestHandler):
        def get(self):
            self.current_user()
     
            self.render('login.html', **{'status': ''})
     
        def post(self, *args, **kwargs):
     
            username = self.get_argument('name')
            password = self.get_argument('pwd')
            if username == 'alex' and password == '123':
                self.set_secure_cookie('login_user', 'alex')
                self.redirect('/')
            else:
                self.render('login.html', **{'status': '用户名或密码错误'})
     
    settings = {
        'template_path': 'template',
        'static_path': 'static',
        'static_url_prefix': '/static/',
        'cookie_secret': 'helldjkaskak',  # 设定加一段字符串的cookie
    }
     
    application = tornado.web.Application([
        (r"/index", MainHandler),
        (r"/login", LoginHandler),
    ], **settings)
     
     
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    自定义登录验证

    d、JavaScript操作Cookie

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

    /*
    设置cookie,指定秒数过期,
    name表示传入的key,
    value表示传入相对应的value值,
    expires表示当前日期在加5秒过期
     */
    
    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();
    }
    

      

      5、Session

     除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥。

    操作session

    • 获取session:request.session[key]
    • 设置session:reqeust.session[key] = value
    • 删除session:del request[key]

    区别:cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import tornado.ioloop
    import tornado.web
    from hashlib import sha1
    import os, time
    
    session_container = {}
    
    create_session_id = lambda: sha1('%s%s' % (os.urandom(16), time.time())).hexdigest()
    
    
    class Session(object):
    
        session_id = "__sessionId__"
    
        def __init__(self, request):
            #当你请求过来的时候,我先去get_cookie看看有没有cookie!目的是看看有没有Cookie如果有的话就不生成了,没有就生成!
            session_value = request.get_cookie(Session.session_id)
            #如果没有Cookie生成Cookie[创建随机字符串]
            if not session_value:
                self._id = create_session_id()
            else:
                #如果有直接将客户端的随机字符串设置给_id这个字段,随机字符串封装到self._id里了
                self._id = session_value
            #在给它设置一下
            request.set_cookie(Session.session_id, self._id)
    
        def __getitem__(self, key):
            ret = None
            try:
                ret =  session_container[self._id][key]
            except Exception,e:
                pass
            return ret
    
    
        def __setitem__(self, key, value):
            #判断是否有这个随机字符串
            if session_container.has_key(self._id):
                session_container[self._id][key] = value
            else:
                #如果没有就生成一个字典
                '''
                类似:随机字符串:{'IS_LOGIN':'True'}
                '''
                session_container[self._id] = {key: value}
    
        def __delitem__(self, key):
            del session_container[self._id][key]
    
    
    class BaseHandler(tornado.web.RequestHandler):
    
        def initialize(self):
            '''
            这里initialize的self是谁?
            obj = LoginHandler()
            obj.initialize() ==>这里LoginHandler这个类里没有initialize这个方法,在他父类里有
            所以initialize得self就是LoginHandler的对象
            '''
            self.my_session = Session(self) #执行Session的构造方法并且把LoginHandler的对象传过去
            '''
            这个self.my_session = Session()
            看这个例子:
            self.xxx = '123'  在这里创建一个对象,在LoginHandler中是否可以通过self.xxx去访问123这个值?
            可以,因为self.xxx 是在get之前执行的,他们俩的对象都是LoginHandler对象
            '''
    
    class MainHandler(BaseHandler):
    
        def get(self):
            ret = self.my_session['is_login']
            if ret:
                self.write('index')
            else:
                self.redirect("/login")
    
    class LoginHandler(BaseHandler):
        def get(self):
            '''
            当用户访登录的时候我们就得给他写cookie了,但是这里没有写在哪里写了呢?
            在哪里呢?之前写的Handler都是继承的RequestHandler,这次继承的是BaseHandler是自己写的Handler
            继承自己的类,在类了加扩展initialize! 在这里我们可以在这里做获取用户cookie或者写cookie都可以在这里做
            '''
            '''
            我们知道LoginHandler对象就是self,我们可不可以self.set_cookie()可不可以self.get_cookie()
            '''
            # self.set_cookie()
            # self.get_cookie()
    
            self.render('login.html', **{'status': ''})
    
        def post(self, *args, **kwargs):
            #获取用户提交的用户名和密码
            username = self.get_argument('username')
            password = self.get_argument('pwd')
            if username == 'wupeiqi' and password == '123':
                #如果认证通过之后就可以访问这个self.my_session对象了!然后我就就可以吧Cookie写入到字典中了,NICE
                self.my_session['is_login'] = 'true'
    
                '''
                这里用到知识点是类里的:
                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'] #自动触发执行  __getitem__
                obj['k2'] = 'wupeiqi' #自动触发执行 __setitem__
                del obj['k1'] #自动触发执行  __delitme__
    
                '''
    
                self.redirect('/index')
            else:
                self.render('login.html', **{'status': '用户名或密码错误'})
    
    
    
    settings = {
        'template_path': 'template',
        'static_path': 'static',
        'static_url_prefix': '/static/',
        'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',
        'login_url': '/login'
    }
    
    application = tornado.web.Application([
        #创建两个URL 分别对应  MainHandler  LoginHandler
        (r"/index", MainHandler),
        (r"/login", LoginHandler),
    ], **settings)
    
    
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    View Code
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import tornado.web
    import tornado.ioloop
    
    container = {}
    class Session:
        def __init__(self, handler):
            self.handler = handler
            self.random_str = None
    
        def __genarate_random_str(self):
            import hashlib
            import time
            obj = hashlib.md5()
            obj.update(bytes(str(time.time()), encoding='utf-8'))
            random_str = obj.hexdigest()
            return random_str
    
        def __setitem__(self, key, value):
            # 在container中加入随机字符串
            # 定义专属于自己的数据
            # 在客户端中写入随机字符串
            # 判断,请求的用户是否已有随机字符串
            if not self.random_str:
                random_str = self.handler.get_cookie('__session__')
                if not random_str:
                    random_str = self.__genarate_random_str()
                    container[random_str] = {}
                else:
                    # 客户端有随机字符串
                    if random_str in container.keys():
                        pass
                    else:
                        random_str = self.__genarate_random_str()
                        container[random_str] = {}
                self.random_str = random_str # self.random_str = asdfasdfasdfasdf
    
            container[self.random_str][key] = value
            self.handler.set_cookie("__session__", self.random_str)
    
        def __getitem__(self, key):
            # 获取客户端的随机字符串
            # 从container中获取专属于我的数据
            #  专属信息【key】
            random_str =  self.handler.get_cookie("__session__")
            if not random_str:
                return None
            # 客户端有随机字符串
            user_info_dict = container.get(random_str,None)
            if not user_info_dict:
                return None
            value = user_info_dict.get(key, None)
            return value
    
    
    class BaseHandler(tornado.web.RequestHandler):
        def initialize(self):
            self.session = Session(self)
    自定义session

      6、上传文件

    6.1、Form表单上传

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <input type="file" id="img" />
        <input type="button" onclick="UploadFile();" />
        <script src="/statics/jquery-1.12.4.js">
            function UploadFile(){
                var fileObj = $("#img")[0].files[0];
                var form = new FormData();
                form.append("user", "v1");
                form.append("favor", "1");
                form.append("fafafa", "fileObj");
    
                $.ajax({
                    type:'POST',
                    url:'/index',
                    data:form,
                     processData: false,  // tell jQuery not to process the data
                    contentType: false,  // tell jQuery not to set contentType
                    success: function(arg) {
                        console.log(arg);
                    }
                })
            }
        </script>
    
    </body>
    </html>
    index
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import tornado.ioloop
    import tornado.web
    
    IMG_LIST = []
    class IndexHandler(tornado.web.RequestHandler):
        def get(self):
            self.render('index.html', img_list=IMG_LIST)
        def post(self, *args, **kwargs):
            print(self.get_argument('user'))
            print(self.get_arguments('favor'))
            file_metas = self.request.files["fafafa"]
            # print(file_metas)
            for meta in file_metas:
                # 要上传的文件名
                file_name = meta['filename']
                import os
                with open(os.path.join('statics', 'img', file_name), 'wb') as up:
                    up.write(meta['body'])
                IMG_LIST.append(file_name)
            self.write('{"status": 1, "message": "mmmm"}')
    
    settings = {
        'template_path': 'views',
        'static_path': 'statics',
        'static_url_prefix': '/statics/',
    }
    
    application = tornado.web.Application([
        (r"/index", IndexHandler),
    ], **settings)
    
    
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    start

    源码文件夹:http://pan.baidu.com/s/1slL6gFV

    6.2、AJAX上传

      xhr上传
      jquery上传
      基于iframe上传

    源码文件夹:http://pan.baidu.com/s/1slL6gFV

      7、验证码

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

    下面也有具体的验证代码,可仿照。

    源码文件夹:http://pan.baidu.com/s/1slL6gFV

    自定义Web组件

      1、面向对象基础

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

    #!/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才能实现。

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
      
    import tornado.ioloop
    import tornado.web
    from hashlib import sha1
    import os, time
      
    session_container = {}
      
    create_session_id = lambda: sha1('%s%s' % (os.urandom(16), time.time())).hexdigest()
      
      
    class Session(object):
      
        session_id = "__sessionId__"
      
        def __init__(self, request):
            session_value = request.get_cookie(Session.session_id)
            if not session_value:
                self._id = create_session_id()
            else:
                self._id = session_value
            request.set_cookie(Session.session_id, self._id)
      
        def __getitem__(self, key):
            return session_container[self._id][key]
      
        def __setitem__(self, key, value):
            if session_container.has_key(self._id):
                session_container[self._id][key] = value
            else:
                session_container[self._id] = {key: value}
      
        def __delitem__(self, key):
            del session_container[self._id][key]
      
      
    class BaseHandler(tornado.web.RequestHandler):
      
        def initialize(self):
            # my_session['k1']访问 __getitem__ 方法
            self.my_session = Session(self)
      
      
    class MainHandler(BaseHandler):
      
        def get(self):
            print self.my_session['c_user']
            print self.my_session['c_card']
            self.write('index')
      
    class LoginHandler(BaseHandler):
      
        def get(self):
            self.render('login.html', **{'status': ''})
      
        def post(self, *args, **kwargs):
      
            username = self.get_argument('name')
            password = self.get_argument('pwd')
            if username == 'wupeiqi' and password == '123':
      
                self.my_session['c_user'] = 'wupeiqi'
                self.my_session['c_card'] = '12312312309823012'
      
                self.redirect('/index')
            else:
                self.render('login.html', **{'status': '用户名或密码错误'})
      
    settings = {
        'template_path': 'template',
        'static_path': 'static',
        'static_url_prefix': '/static/',
        'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',
        'login_url': '/login'
    }
      
    application = tornado.web.Application([
        (r"/index", MainHandler),
        (r"/login", LoginHandler),
    ], **settings)
      
      
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    
    自定义Session
    

      

      4、表单验证

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

    <!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>
        <form action="/index" method="post">
    
            <p>hostname: <input type="text" name="host" /> </p>
            <p>ip: <input type="text" name="ip" /> </p>
            <p>port: <input type="text" name="port" /> </p>
            <p>phone: <input type="text" name="phone" /> </p>
            <input type="submit" />
        </form>
    </body>
    </html>
    HTML
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
      
    import tornado.ioloop
    import tornado.web
    from hashlib import sha1
    import os, time
    import re
      
      
    class MainForm(object):
        def __init__(self):
            self.host = "(.*)"
            self.ip = "^(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}$"
            self.port = '(d+)'
            self.phone = '^1[3|4|5|8][0-9]d{8}$'
      
        def check_valid(self, request):
            form_dict = self.__dict__
            for key, regular in form_dict.items():
                post_value = request.get_argument(key)
                # 让提交的数据 和 定义的正则表达式进行匹配
                ret = re.match(regular, post_value)
                print key,ret,post_value
      
      
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            self.render('index.html')
        def post(self, *args, **kwargs):
            obj = MainForm()
            result = obj.check_valid(self)
            self.write('ok')
      
      
      
    settings = {
        'template_path': 'template',
        'static_path': 'static',
        'static_url_prefix': '/static/',
        'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',
        'login_url': '/login'
    }
      
    application = tornado.web.Application([
        (r"/index", MainHandler),
    ], **settings)
      
      
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    
    Python
    python

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

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import tornado.ioloop
    import tornado.web
    import re
    
    
    class Field(object):
    
        def __init__(self, error_msg_dict, required):
            self.id_valid = False
            self.value = None
            self.error = None
            self.name = None
            self.error_msg = error_msg_dict
            self.required = required
    
        def match(self, name, value):
            self.name = name
    
            if not self.required:
                self.id_valid = True
                self.value = value
            else:
                if not value:
                    if self.error_msg.get('required', None):
                        self.error = self.error_msg['required']
                    else:
                        self.error = "%s is required" % name
                else:
                    ret = re.match(self.REGULAR, value)
                    if ret:
                        self.id_valid = True
                        self.value = ret.group()
                    else:
                        if self.error_msg.get('valid', None):
                            self.error = self.error_msg['valid']
                        else:
                            self.error = "%s is invalid" % name
    
    
    class IPField(Field):
        REGULAR = "^(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}$"
    
        def __init__(self, error_msg_dict=None, required=True):
    
            error_msg = {}  # {'required': 'IP不能为空', 'valid': 'IP格式错误'}
            if error_msg_dict:
                error_msg.update(error_msg_dict)
    
            super(IPField, self).__init__(error_msg_dict=error_msg, required=required)
    
    
    class IntegerField(Field):
        REGULAR = "^d+$"
    
        def __init__(self, error_msg_dict=None, required=True):
            error_msg = {'required': '数字不能为空', 'valid': '数字格式错误'}
            if error_msg_dict:
                error_msg.update(error_msg_dict)
    
            super(IntegerField, self).__init__(error_msg_dict=error_msg, required=required)
    
    
    class CheckBoxField(Field):
    
        def __init__(self, error_msg_dict=None, required=True):
            error_msg = {}  # {'required': 'IP不能为空', 'valid': 'IP格式错误'}
            if error_msg_dict:
                error_msg.update(error_msg_dict)
    
            super(CheckBoxField, self).__init__(error_msg_dict=error_msg, required=required)
    
        def match(self, name, value):
            self.name = name
    
            if not self.required:
                self.id_valid = True
                self.value = value
            else:
                if not value:
                    if self.error_msg.get('required', None):
                        self.error = self.error_msg['required']
                    else:
                        self.error = "%s is required" % name
                else:
                    if isinstance(name, list):
                        self.id_valid = True
                        self.value = value
                    else:
                        if self.error_msg.get('valid', None):
                            self.error = self.error_msg['valid']
                        else:
                            self.error = "%s is invalid" % name
    
    
    class FileField(Field):
        REGULAR = "^(w+.pdf)|(w+.mp3)|(w+.py)$"
    
        def __init__(self, error_msg_dict=None, required=True):
            error_msg = {}  # {'required': '数字不能为空', 'valid': '数字格式错误'}
            if error_msg_dict:
                error_msg.update(error_msg_dict)
    
            super(FileField, self).__init__(error_msg_dict=error_msg, required=required)
    
        def match(self, name, value):
            self.name = name
            self.value = []
            if not self.required:
                self.id_valid = True
                self.value = value
            else:
                if not value:
                    if self.error_msg.get('required', None):
                        self.error = self.error_msg['required']
                    else:
                        self.error = "%s is required" % name
                else:
                    m = re.compile(self.REGULAR)
                    if isinstance(value, list):
                        for file_name in value:
                            r = m.match(file_name)
                            if r:
                                self.value.append(r.group())
                                self.id_valid = True
                            else:
                                self.id_valid = False
                                if self.error_msg.get('valid', None):
                                    self.error = self.error_msg['valid']
                                else:
                                    self.error = "%s is invalid" % name
                                break
                    else:
                        if self.error_msg.get('valid', None):
                            self.error = self.error_msg['valid']
                        else:
                            self.error = "%s is invalid" % name
    
        def save(self, request, upload_path=""):
    
            file_metas = request.files[self.name]
            for meta in file_metas:
                file_name = meta['filename']
                with open(file_name,'wb') as up:
                    up.write(meta['body'])
    
    
    class Form(object):
    
        def __init__(self):
            self.value_dict = {}
            self.error_dict = {}
            self.valid_status = True
    
        def validate(self, request, depth=10, pre_key=""):
    
            self.initialize()
            self.__valid(self, request, depth, pre_key)
    
        def initialize(self):
            pass
    
        def __valid(self, form_obj, request, depth, pre_key):
            """
            验证用户表单请求的数据
            :param form_obj: Form对象(Form派生类的对象)
            :param request: Http请求上下文(用于从请求中获取用户提交的值)
            :param depth: 对Form内容的深度的支持
            :param pre_key: Html中name属性值的前缀(多层Form时,内部递归时设置,无需理会)
            :return: 是否验证通过,True:验证成功;False:验证失败
            """
    
            depth -= 1
            if depth < 0:
                return None
            form_field_dict = form_obj.__dict__
            for key, field_obj in form_field_dict.items():
                print key,field_obj
                if isinstance(field_obj, Form) or isinstance(field_obj, Field):
                    if isinstance(field_obj, Form):
                        # 获取以key开头的所有的值,以参数的形式传至
                        self.__valid(field_obj, request, depth, key)
                        continue
                    if pre_key:
                        key = "%s.%s" % (pre_key, key)
    
                    if isinstance(field_obj, CheckBoxField):
                        post_value = request.get_arguments(key, None)
                    elif isinstance(field_obj, FileField):
                        post_value = []
                        file_list = request.request.files.get(key, None)
                        for file_item in file_list:
                            post_value.append(file_item['filename'])
                    else:
                        post_value = request.get_argument(key, None)
    
                    print post_value
                    # 让提交的数据 和 定义的正则表达式进行匹配
                    field_obj.match(key, post_value)
                    if field_obj.id_valid:
                        self.value_dict[key] = field_obj.value
                    else:
                        self.error_dict[key] = field_obj.error
                        self.valid_status = False
    
    
    class ListForm(object):
        def __init__(self, form_type):
            self.form_type = form_type
            self.valid_status = True
            self.value_dict = {}
            self.error_dict = {}
    
        def validate(self, request):
            name_list = request.request.arguments.keys() + request.request.files.keys()
            index = 0
            flag = False
            while True:
                pre_key = "[%d]" % index
                for name in name_list:
                    if name.startswith(pre_key):
                        flag = True
                        break
                if flag:
                    form_obj = self.form_type()
                    form_obj.validate(request, depth=10, pre_key="[%d]" % index)
                    if form_obj.valid_status:
                        self.value_dict[index] = form_obj.value_dict
                    else:
                        self.error_dict[index] = form_obj.error_dict
                        self.valid_status = False
                else:
                    break
    
                index += 1
                flag = False
    
    
    class MainForm(Form):
    
        def __init__(self):
            # self.ip = IPField(required=True)
            # self.port = IntegerField(required=True)
            # self.new_ip = IPField(required=True)
            # self.second = SecondForm()
            self.fff = FileField(required=True)
            super(MainForm, self).__init__()
    
    #
    # class SecondForm(Form):
    #
    #     def __init__(self):
    #         self.ip = IPField(required=True)
    #         self.new_ip = IPField(required=True)
    #
    #         super(SecondForm, self).__init__()
    
    
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            self.render('index.html')
        def post(self, *args, **kwargs):
            # for i in  dir(self.request):
            #     print i
            # print self.request.arguments
            # print self.request.files
            # print self.request.query
            # name_list = self.request.arguments.keys() + self.request.files.keys()
            # print name_list
    
            # list_form = ListForm(MainForm)
            # list_form.validate(self)
            #
            # print list_form.valid_status
            # print list_form.value_dict
            # print list_form.error_dict
    
            # obj = MainForm()
            # obj.validate(self)
            #
            # print "验证结果:", obj.valid_status
            # print "符合验证结果:", obj.value_dict
            # print "错误信息:"
            # for key, item in obj.error_dict.items():
            #     print key,item
            # print self.get_arguments('favor'),type(self.get_arguments('favor'))
            # print self.get_argument('favor'),type(self.get_argument('favor'))
            # print type(self.get_argument('fff')),self.get_argument('fff')
            # print self.request.files
            # obj = MainForm()
            # obj.validate(self)
            # print obj.valid_status
            # print obj.value_dict
            # print obj.error_dict
            # print self.request,type(self.request)
            # obj.fff.save(self.request)
            # from tornado.httputil import HTTPServerRequest
            # name_list = self.request.arguments.keys() + self.request.files.keys()
            # print name_list
            # print self.request.files,type(self.request.files)
            # print len(self.request.files.get('fff'))
            
            # obj = MainForm()
            # obj.validate(self)
            # print obj.valid_status
            # print obj.value_dict
            # print obj.error_dict
            # obj.fff.save(self.request)
            self.write('ok')
    
    
    
    settings = {
        'template_path': 'template',
        'static_path': 'static',
        'static_url_prefix': '/static/',
        'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',
        'login_url': '/login'
    }
    
    application = tornado.web.Application([
        (r"/index", MainHandler),
    ], **settings)
    
    
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    View Code

      5、tornado生成随机验证码

    用python生成随机验证码需要借鉴一个插件,和一个io模块,实现起来也非常容易,当然也需要借鉴session来判断验证码是否错误,

    下面写一段用户登录验证带验证码的,再看下效果,插件必须和执行文件必须放在更目录下

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import tornado.web
    import tornado.ioloop
    
    container = {}
    class Session:
        def __init__(self, handler):
            self.handler = handler
            self.random_str = None
    
        def __genarate_random_str(self):
            import hashlib
            import time
            obj = hashlib.md5()
            obj.update(bytes(str(time.time()), encoding='utf-8'))
            random_str = obj.hexdigest()
            return random_str
    
        def __setitem__(self, key, value):
            # 在container中加入随机字符串
            # 定义专属于自己的数据
            # 在客户端中写入随机字符串
            # 判断,请求的用户是否已有随机字符串
            if not self.random_str:
                random_str = self.handler.get_cookie('__session__')
                if not random_str:
                    random_str = self.__genarate_random_str()
                    container[random_str] = {}
                else:
                    # 客户端有随机字符串
                    if random_str in container.keys():
                        pass
                    else:
                        random_str = self.__genarate_random_str()
                        container[random_str] = {}
                self.random_str = random_str # self.random_str = asdfasdfasdfasdf
    
            container[self.random_str][key] = value
            self.handler.set_cookie("__session__", self.random_str)
    
        def __getitem__(self, key):
            # 获取客户端的随机字符串
            # 从container中获取专属于我的数据
            #  专属信息【key】
            random_str =  self.handler.get_cookie("__session__")
            if not random_str:
                return None
            # 客户端有随机字符串
            user_info_dict = container.get(random_str,None)
            if not user_info_dict:
                return None
            value = user_info_dict.get(key, None)
            return value
    
    
    class BaseHandler(tornado.web.RequestHandler):
        def initialize(self):
            self.session = Session(self)
    
    
    class LoginHandler(BaseHandler):
        def get(self, *args, **kwargs):
            self.render('login.html' ,state = "")
    
        def post(self, *args, **kwargs):
            username = self.get_argument('username')
            password = self.get_argument('password')
            code =self.get_argument('code')
            check_code = self.session['CheckCode']
            if username =="zhangyanlin" and password == "123" and code.upper() == check_code.upper():
                self.write("登录成功")
            else:
                self.render('login.html',state = "验证码错误")
    
    class CheckCodeHandler(BaseHandler):
        def get(self, *args, **kwargs):
            import io
            import check_code
            mstream = io.BytesIO()
            img,code = check_code.create_validate_code()
            img.save(mstream,"GIF")
            self.session['CheckCode'] =code
            self.write(mstream.getvalue())
    
    
    settings = {
        'template_path':'views',
        'cookie_secret': "asdasd",
    }
    
    application = tornado.web.Application([
        (r'/login',LoginHandler),
        (r'/check_code',CheckCodeHandler)
    ],**settings)
    
    if __name__ == '__main__':
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    stater.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>验证码</title>
    </head>
    <body>
        <form action="/login" method="post">
            <p>用户名: <input type="text" name="username"> </p>
            <p>密码: <input type="password" name="password"> </p>
            <p>验证码: <input type="text" name="code"><img src="/check_code" onclick="ChangeCode();" id = "checkcode"></p>
            <input type="submit" value="submit"> <span>{{state}}</span>
        </form>
    <script type="text/javascript">  //当点击图片的时候,会刷新图片,这一段代码就可以实现
        function ChangeCode() {
            var code = document.getElementById('checkcode');
            code.src += "?";
        }
    </script>
    </body>
    </html>
    login.py

    效果如下:

    上面实例的源码文件夹:http://pan.baidu.com/s/1slL6gFV

    更多Tornado知识详见:http://demo.pythoner.com/itt2zh/ch1.html

    http://www.cnblogs.com/wupeiqi/articles/5702910.html

    http://www.cnblogs.com/luotianshuai/p/5386494.html

  • 相关阅读:
    三、DQL语言
    四、DML语言
    五、DDL语言
    Set WebClient Timeout and reference Stackoverflow
    C# anonymous types and serialization
    C# get multiple folders size under upper folder and order them by size descendingly.
    C# NamedPipeServerStream NamedPipeClientStream
    Convert XLSX file to DataTable via NPOI
    C# NPOI read excel files include xls and xlsx
    C# write stream to local file
  • 原文地址:https://www.cnblogs.com/kongqi816-boke/p/5699866.html
Copyright © 2011-2022 走看看