tornodo 初级

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

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

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

一、快速上手

#!/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 ...)的不同调用并执行相应的方法

第五步:方法返回值的字符串内容发送浏览器

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web
from tornado import httpclient
from tornado.web import asynchronous
from tornado import gen

import uimodules as md
import uimethods as mt

class MainHandler(tornado.web.RequestHandler):
        @asynchronous
        @gen.coroutine
        def get(self):
            print 'start get '
            http = httpclient.AsyncHTTPClient()
            http.fetch("http://127.0.0.1:8008/post/", self.callback)
            self.write('end')

        def callback(self, response):
            print response.body

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()
异步非阻塞实例

二、路由系统

路由系统其实就是 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 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()

需要修改hosts   C:\Windows\System32\drivers\etc 

http://wupeiqi.com:8000/index  二级域名只是相当于127.0.0.1  还需要自己加端口号

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

三、模板

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

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

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

 

{% include "../include/form.html" %} 调用其他模块的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>
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
#!/usr/bin/env python
# -*- coding:utf-8 -*-
  
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()

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

  • 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 的別名

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

1、定义

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

2、注册

#!/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

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

 

练习

 

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>老男孩</title>
    <link rel="stylesheet" href="static/commons.css">
</head>
<body>
    <h1>提交内容</h1>
    <form method="post" action="/index">
        <input type="text" name="xxx">
        <input type="submit" value="提交">
    </form>
    <h1>展示内容</h1>
    <h2>{{npm}}</h2>
    <h3>{{ func(npm) }}</h3>
    <h3>{% module custom() %}</h3>
    <ul>
        {% for item in xxxooo %}
            {% if item == "alex" %}
                <li style="color: red">{{item}}</li>
            {% else %}
                <li>{{itrm}}</li>
            {% end %}
        {% end %}
    </ul>

</body>
</html>
s1

 

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import uimethod as mt
import  uimodule as md


INPUTS_LIST = []
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("s1.html",npm='NPM999',xxxooo = INPUTS_LIST )
    def post(self, *args, **kwargs):
        name = self.get_argument("xxx")
        self.write("Hello, world")
        INPUTS_LIST.append(name)
        self.render("s1.html",npm='NPM999',xxxooo = INPUTS_LIST)


settings = {
    "template_path":"tpl",
    "static_path":"static",
    "ui_methods":mt,
    "ui_modules":md,
}

application = tornado.web.Application([
    (r"/index",MainHandler),
    ],**settings)
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
s1.python
#!/usr/bin/env python
# -*- coding:utf-8 -*-

def func(self,age):
    return  age.lower()
uimethod.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 "1234"
uimodule

 

 

 

 

四、实用功能

1、静态文件

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
import tornado.ioloop
import tornado.web
 
 
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('home/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(80)
    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

备注:静态文件缓存的实现

    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()
静态文件缓存源码

 

'template_path': 'tpl', # 模板路径的配置
'static_path': 'static', #静态文件路径
'static_url_prefix': '/sss/', #别名
静态文件加载到浏览器 MD5值得形式  下次浏览时比对如果没变化就不修改   <script src='{{ static_url("oldboy.js") }}'></script>
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import uimethod as mt
import uimodule as md


INPUTS_LIST = []
USER_INFO = {'is_login': None}
NEWS_LIST = [
    {"title": '索宁被锁住了', "content": "好期待呀..."},
    {"title": '索宁真的被锁住了', "content": "太爽了..."}
]

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        # self.write("Hello, world")
        # 1、打开s1.html文件,读取内容(包含特殊语法)
        # 2、xxxooo = [11,22,33,44] && 读取内容(包含特殊语法)
        # 3、得到新的字符串
        # 4、返回给用户
        name = self.get_argument('xxx',None)
        if name:
            INPUTS_LIST.append(name)
        self.render("s1.html", npm="NPM888", xxxooo= INPUTS_LIST )
    # def post(self, *args, **kwargs):
    #     name = self.get_argument('xxx')
    #     INPUTS_LIST.append(name)
    #     self.render("s1.html",  xxxooo= INPUTS_LIST)


class IndexHandler(tornado.web.RequestHandler):

    def get(self, *args, **kwargs):
        self.render('index.html',user_info = USER_INFO, new_list=NEWS_LIST)

class LoginHandler(tornado.web.RequestHandler):

    def post(self, *args, **kwargs):
        username = self.get_argument('username',None)
        pwd = self.get_argument('pwd',None)
        if username == 'alex' and pwd == "123":
            USER_INFO['is_login'] = True
            USER_INFO['username'] = username
        self.render('index.html',user_info = USER_INFO)
class PublishHandler(tornado.web.RequestHandler):

    def post(self, *args, **kwargs):
        title = self.get_argument('title',None)
        content = self.get_argument('content',None)
        temp = {'title':title, "content": content}
        NEWS_LIST.append(temp)
        # self.render('index.html',user_info = USER_INFO)
        self.redirect('/index')
settings = {
    'template_path': 'tpl', # 模板路径的配置
    'static_path': 'static',  #静态文件路径
    'static_url_prefix': '/sss/', #
    'ui_methods': mt,
    'ui_modules': md,
}


# 路由映射,路由系统
application = tornado.web.Application([
    # (r"/index", MainHandler),
    (r"/index", IndexHandler),
    (r"/login", LoginHandler),
    (r"/publish", PublishHandler),
], **settings)


if __name__ == "__main__":
    # socket运行起来
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
s1
def func(self,arg):

    return arg.lower()
uimethod.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 "1234"
uimodule.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href='{{ static_url("commons.css") }}'/>
</head>
<body>
    <h1>提交内容:</h1>
    <form method="get" action="/index">
        <input type="text" name="xxx" />
        <input type="submit" value="提交" />
    </form>
    <h1>展示内容:</h1>
    <h3>{{npm}}</h3>
    <h3>{{ func(npm) }}</h3>
    <h3>{% module  custom() %}</h3>
    <ul>
        {% for item in xxxooo %}
            {% if item == "alex" %}
                <li style="color: red">{{item}}</li>
            {% else %}
                <li>{{item}}</li>
            {% end %}

        {% end %}
    </ul>

    <script src='{{ static_url("oldboy.js") }}'></script>
</body>
</html>
View Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href='{{ static_url("commons.css") }}'/>
</head>
<body>
    <h1>提交内容:</h1>
    <form method="get" action="/index">
        <input type="text" name="xxx" />
        <input type="submit" value="提交" />
    </form>
    <h1>展示内容:</h1>
    <h3>{{npm}}</h3>
    <h3>{{ func(npm) }}</h3>
    <h3>{% module  custom() %}</h3>
    <ul>
        {% for item in xxxooo %}
            {% if item == "alex" %}
                <li style="color: red">{{item}}</li>
            {% else %}
                <li>{{item}}</li>
            {% end %}

        {% end %}
    </ul>

    <script src='{{ static_url("oldboy.js") }}'></script>
</body>
</html>
index

 href="{{static_url('css/zhuce.css')}}  会自动添加static_url_prefix 后面的路径,相当于给static_path起了另一个名字自动添加   如果不是这种需要加上static_path路径,


 

 

2、csrf

发post请求时做限制用的(防止别人盗取你的url给服务器发请求)

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

 {% raw xsrf_form_html() %} 会解析成一个input 标签 自动隐藏

'static_url_prefix': '/statics/',  别名两个/  /

<!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>
        <p>
            <input name="code" type="text" placeholder="验证码"/>
            <img src="/check_code" onclick='ChangeCode();' id='imgCode'>
        </p>
        <input type="submit" value="Submit" /> <span style="color:red"></span>
    </form>
    <script src="/statics/jquery-1.12.4.js"></script>
    <input type="button" value="Ajax CSRF" onclick="SubmitCsrf();" />
    <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.html
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
container = {}
# container = {
#     # "第一个人的随机字符串":{},
#     # "第一个人的随机字符串":{'k1': 111, 'parents': '你'},
# }

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('__kakaka__')
            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("__kakaka__", self.random_str)

    def __getitem__(self,key):
        # 获取客户端的随机字符串
        # 从container中获取专属于我的数据
        #  专属信息【key】
        random_str =  self.handler.get_cookie("__kakaka__")
        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 IndexHandler(BaseHandler):
    def get(self):
        if self.get_argument('u', None) in ['alex', 'eric']:
            self.session['is_login'] = True
            self.session['name'] = self.get_argument('u', None)
            # self.session.set_value('is_login', True)
            # self.session.set_value('name', self.get_argument('u', None))
            print(container)
        else:
            self.write('请登录')
class ManagerHandler(BaseHandler):
    def get(self):
        val = self.session['is_login']
        if val:
            self.write(self.session['name'])
        else:
            self.write('失败')


class LoginHandler(BaseHandler):
    def get(self, *args, **kwargs):
        self.render('login.html', status="")
    def post(self, *args, **kwargs):
        user = self.get_argument('user',None)
        pwd = self.get_argument('pwd',None)
        code = self.get_argument('code',None)
        check_code = self.session["CheckCode"]
        if code.upper() == check_code.upper():
            self.write('验证码正确')
        else:
            # self.redirect('/login')
            self.render('login.html', status='验证码错误')

class CheckCodeHandler(BaseHandler):
    def get(self, *args, **kwargs):
        # 生成图片并且返回
        import io
        import check_code
        mstream = io.BytesIO()
        # 创建图片,并写入验证码
        img, code = check_code.create_validate_code()
        # 将图片对象写入到mstream,
        img.save(mstream, "GIF")
        # 为每个用户保存其验证码
        self.session["CheckCode"] = code
        self.write(mstream.getvalue())

class CsrfHandler(BaseHandler):

    def get(self, *args, **kwargs):
        self.render('csrf.html')

    def post(self, *args, **kwargs):
        self.write('csrf.post')

settings = {
    'template_path': 'views',
    'static_path': 'statics',
    'static_url_prefix': '/statics/',
    'cookie_secret': 'asdfasdfasdf',
    'xsrf_cookies': True
}

application = tornado.web.Application([
    (r"/index", IndexHandler),
    (r"/manager", ManagerHandler),
    (r"/login", LoginHandler),
    (r"/check_code", CheckCodeHandler),
    (r"/csrf", CsrfHandler),
], **settings)


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

 

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使用时,本质上就是去获取本地的cookie,携带cookie再来发送请求

3、cookie

在浏览器端保持的键值对,特性:每次http请求都会携带

签名 一定程度上防止伪造

 加密规则

操作cookie的两种方式:

1、tornodo 在后台设置(demain域名默认是当前  expries过期时间(utc全球统一时间) path路径  )

  self.cookes 所有的cookie

  self.set_cookie("k1","9999")

  self.get_cookie("k1")

  1.1设置UTC时间:

    var date = new Date();

    date.setDate(date.getDate() + 7) 天为格式

    date.setSeconds(date.getSeconds() + 7)

    data.toUTCstring()

2、在浏览器上用javascript

  document.cookie 当前页面的所有cookie  得到的是字符串  默认情况cookie就是一个字符串

  setCookie("k88",9090",5)

  document.cookie.split(";") 一步步字节写

  document.cookie = “k2=666”; 添加coookie  浏览器会自动添加

  document.cookie = “k2=666;path=/;”  设置一些  demain域名默认是当前  expries过期时间 path路径

/*

设置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使用

 

3、jQuery Cookie

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="/statics/jquery-1.12.4.js"></script>
<script src="/statics/jquery.cookie.js"></script>
<script>
    // ##################### 通过JavaScript 设置 #####################
    /*
    设置cookie,指定秒数过期
     */
    function setCookieBySeconds(name,value,expires){
        var current_date = new Date();
        current_date.setSeconds(current_date.getSeconds() + expires);
        document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString();
    }
    function setCookieByDays(name,value,expires){
        var current_date = new Date();
        current_date.setDate(current_date.getDate() + expires);
        document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString();
    }
    // setCookieBySeconds('k1','v1', 6); // 6 秒
    // setCookieByDays('k2','v1', 7)     // 7 天

    // ##################### 通过 jQuery 设置 #####################
    //$.cookie('k1', 'v1' ,{expires: 7 });    // 7 天

    //var current_date = new Date();
    //current_date.setSeconds(current_date.getSeconds() + 6);
    //$.cookie('k1', 'v1' ,{expires: current_date }); //6秒


</script>
</body>
</html>
jQuery Cookie

 

  $.cookie("k3","555",{"path":"/","domain":"",expires = 7})

  jQuery Cookie 内部将7转换成7天

 

自己写的

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web
import time
class IndexHandler(tornado.web.RequestHandler):

    def get(self, *args, **kwargs):
        self.render('index.html')

class ManagerHandler(tornado.web.RequestHandler):

    def get(self, *args, **kwargs):
        co = self.get_cookie('auth')
        if co == '1':
            self.render('manager.html')
        else:
            self.redirect("/login")

class LogoutHandler(tornado.web.RequestHandler):

    def get(self, *args, **kwargs):
        self.set_cookie('auth', '1', expires=time.time())
        self.redirect('/login')

class LoginHandler(tornado.web.RequestHandler):

    def get(self, *args, **kwargs):
        self.render('login.html',status_text="")

    def post(self, *args, **kwargs):
        username = self.get_argument('username',None)
        pwd = self.get_argument('password',None)
        check = self.get_argument('auto', None)
        if username == 'alex' and pwd == "sb":

            if check:
                # self.get_secure_cookie()
                self.set_cookie('username', username, expires_days=7)
                self.set_cookie('auth', '1', expires_days=7)
            else:
                r = time.time() + 10
                self.set_cookie('auth', '1', expires=r)
                self.set_cookie('username',username, expires=r)
            self.redirect('/manager')
        else:
            self.render('login.html', status_text="登录失败")

settings = {
    'template_path': 'views', # 模板路径的配置
    'cookie_secret': 'sdfgsdfg'
}

# 路由映射,路由系统
application = tornado.web.Application([
    (r"/index", IndexHandler),
    (r"/login", LoginHandler),
    (r"/manager", ManagerHandler),
    (r"/logout", LogoutHandler),
], **settings)


if __name__ == "__main__":
    # socket运行起来
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
index
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
        <form action="/login" method="post">
            <input type="text" name="username" />
            <input type="password" name="password" />
            <input type="checkbox" name="auto" value="1">7天免登录
            <input type="submit" value="登录" />

            <span style="color: red;">{{status_text}}</span>
        </form>
</body>
</html>
login
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
        <form action="/login" method="post">
            <input type="text" name="username" />
            <input type="password" name="password" />
            <input type="checkbox" name="auto" value="1">7天免登录
            <input type="submit" value="登录" />

            <span style="color: red;">{{status_text}}</span>
        </form>
</body>
</html>
manager
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
        <form action="/login" method="post">
            <input type="text" name="username" />
            <input type="password" name="password" />
            <input type="checkbox" name="auto" value="1">7天免登录
            <input type="submit" value="登录" />

            <span style="color: red;">{{status_text}}</span>
        </form>
</body>
</html>
index.html

 

一、Session

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'] 
View Code

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') 
View Code

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()
View Code

4、分布式Session

一致性哈西

#!/usr/bin/env python
#coding:utf-8

import sys
import math
from bisect import bisect


if sys.version_info >= (2, 5):
    import hashlib
    md5_constructor = hashlib.md5
else:
    import md5
    md5_constructor = md5.new


class HashRing(object):
    """一致性哈希"""
    
    def __init__(self,nodes):
        '''初始化
        nodes : 初始化的节点,其中包含节点已经节点对应的权重
                默认每一个节点有32个虚拟节点
                对于权重,通过多创建虚拟节点来实现
                如:nodes = [
                        {'host':'127.0.0.1:8000','weight':1},
                        {'host':'127.0.0.1:8001','weight':2},
                        {'host':'127.0.0.1:8002','weight':1},
                    ]
        '''
        
        self.ring = dict()
        self._sorted_keys = []

        self.total_weight = 0
        
        self.__generate_circle(nodes)
        
            
            
    def __generate_circle(self,nodes):
        for node_info in nodes:
            self.total_weight += node_info.get('weight',1)
            
        for node_info in nodes:
            weight = node_info.get('weight',1)
            node = node_info.get('host',None)
                
            virtual_node_count = math.floor((32*len(nodes)*weight) / self.total_weight)
            for i in xrange(0,int(virtual_node_count)):
                key = self.gen_key_thirty_two( '%s-%s' % (node, i) )
                if self._sorted_keys.__contains__(key):
                    raise Exception('该节点已经存在.')
                self.ring[key] = node
                self._sorted_keys.append(key)
            
    def add_node(self,node):
        ''' 新建节点
        node : 要添加的节点,格式为:{'host':'127.0.0.1:8002','weight':1},其中第一个元素表示节点,第二个元素表示该节点的权重。
        '''
        node = node.get('host',None)
        if not node:
                raise Exception('节点的地址不能为空.')
                
        weight = node.get('weight',1)
        
        self.total_weight += weight
        nodes_count = len(self._sorted_keys) + 1
        
        virtual_node_count = math.floor((32 * nodes_count * weight) / self.total_weight)
        for i in xrange(0,int(virtual_node_count)):
            key = self.gen_key_thirty_two( '%s-%s' % (node, i) )
            if self._sorted_keys.__contains__(key):
                raise Exception('该节点已经存在.')
            self.ring[key] = node
            self._sorted_keys.append(key)
        
    def remove_node(self,node):
        ''' 移除节点
        node : 要移除的节点 '127.0.0.1:8000'
        '''
        for key,value in self.ring.items():
            if value == node:
                del self.ring[key]
                self._sorted_keys.remove(key)
    
    def get_node(self,string_key):
        '''获取 string_key 所在的节点'''
        pos = self.get_node_pos(string_key)
        if pos is None:
            return None
        return self.ring[ self._sorted_keys[pos]].split(':')
    
    def get_node_pos(self,string_key):
        '''获取 string_key 所在的节点的索引'''
        if not self.ring:
            return None
            
        key = self.gen_key_thirty_two(string_key)
        nodes = self._sorted_keys
        pos = bisect(nodes, key)
        return pos
    
    def gen_key_thirty_two(self, key):
        
        m = md5_constructor()
        m.update(key)
        return long(m.hexdigest(), 16)
        
    def gen_key_sixteen(self,key):
        
        b_key = self.__hash_digest(key)
        return self.__hash_val(b_key, lambda x: x)

    def __hash_val(self, b_key, entry_fn):
        return (( b_key[entry_fn(3)] << 24)|(b_key[entry_fn(2)] << 16)|(b_key[entry_fn(1)] << 8)| b_key[entry_fn(0)] )

    def __hash_digest(self, key):
        m = md5_constructor()
        m.update(key)
        return map(ord, m.digest())


"""
nodes = [
    {'host':'127.0.0.1:8000','weight':1},
    {'host':'127.0.0.1:8001','weight':2},
    {'host':'127.0.0.1:8002','weight':1},
]

ring = HashRing(nodes)
result = ring.get_node('98708798709870987098709879087')
print result

"""
View Code
from hashlib import sha1
import os, time


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):
        # 根据 self._id ,在一致性哈西中找到其对应的服务器IP
        # 找到相对应的redis服务器,如: r = redis.StrictRedis(host='localhost', port=6379, db=0)
        # 使用python redis api 链接
        # 获取数据,即:
        # return self._redis.hget(self._id, name)

    def __setitem__(self, key, value):
        # 根据 self._id ,在一致性哈西中找到其对应的服务器IP
        # 使用python redis api 链接
        # 设置session
        # self._redis.hset(self._id, name, value)


    def __delitem__(self, key):
        # 根据 self._id 找到相对应的redis服务器
        # 使用python redis api 链接
        # 删除,即:
        return self._redis.hdel(self._id, name)
View Code

课上代码

 

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
container = {}
# container = {
#     # "第一个人的随机字符串":{},
#     # "第一个人的随机字符串":{'k1': 111, 'parents': '你'},
# }

class Session:

    def __init__(self, handler):
        self.handler = handler


    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 set_value(self, key,value):
        # 在container中加入随机字符串
        # 定义专属于自己的数据
        # 在客户端中写入随机字符串
        random_str = self.__genarate_random_str()
        container[random_str] = {}
        container[random_str][key] = value
        self.handler.set_cookie("__kakaka__", random_str)

    def get_value(self,key):
        # 获取客户端的随机字符串
        # 从container中获取专属于我的数据
        #  专属信息【key】
        random_str =  self.handler.get_cookie("__kakaka__")
        user_info_dict = container[random_str]
        value = user_info_dict[key]
        return value







class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        Session(self)
        if self.get_argument('u', None) in ['alex', 'eric']:
            import hashlib
            import time
            obj = hashlib.md5()
            obj.update(bytes(str(time.time()),encoding='utf-8'))
            random_str = obj.hexdigest()
            container[random_str] = {}
            # 我希望在以后is_login用户是否已经
            container[random_str]['k1'] = 123
            container[random_str]['k2'] = self.get_argument('u', None) + "parents"
            # 我希望在以后is_login用户是否已经
            container[random_str]['is_login'] = True
            self.set_cookie('iiiiiiiii', random_str)
        else:
            self.write('请登录')
class ManagerHandler(tornado.web.RequestHandler):
    def get(self):
        random_str = self.get_cookie('iiiiiiiii')
        current_user_info = container.get(random_str,None)
        if not current_user_info:
            self.redirect('/index')
        else:
            if current_user_info.get('is_login', None):
                temp = "%s - %s" %(current_user_info.get('k1', ""),current_user_info.get('k2', ""))
                self.write(temp)
            else:
                self.redirect('/index')



settings = {
    'template_path': 'views',
    'static_path': 'statics',
    'cookie_secret': 'asdfasdfasdf'
}

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


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

 

 

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

self_secure_cokie 加密的

参数:doain 域名  默认当前页面

     path 制定路径  /全局

a、基本操作

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!")
Code

b、签名

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=")
Code
def _create_signature_v1(secret, *parts):
    hash = hmac.new(utf8(secret), digestmod=hashlib.sha1)
    for part in parts:
        hash.update(utf8(part))
    return utf8(hash.hexdigest())


def _create_signature_v2(secret, s):
    hash = hmac.new(utf8(secret), digestmod=hashlib.sha256)
    hash.update(utf8(s))
    return utf8(hash.hexdigest())
内部算法
def create_signed_value(secret, name, value, version=None, clock=None,
                        key_version=None):
    if version is None:
        version = DEFAULT_SIGNED_VALUE_VERSION
    if clock is None:
        clock = time.time

    timestamp = utf8(str(int(clock())))
    value = base64.b64encode(utf8(value))
    if version == 1:
        signature = _create_signature_v1(secret, name, value, timestamp)
        value = b"|".join([value, timestamp, signature])
        return value
    elif version == 2:
        # The v2 format consists of a version number and a series of
        # length-prefixed fields "%d:%s", the last of which is a
        # signature, all separated by pipes.  All numbers are in
        # decimal format with no leading zeros.  The signature is an
        # HMAC-SHA256 of the whole string up to that point, including
        # the final pipe.
        #
        # The fields are:
        # - format version (i.e. 2; no length prefix)
        # - key version (integer, default is 0)
        # - timestamp (integer seconds since epoch)
        # - name (not encoded; assumed to be ~alphanumeric)
        # - value (base64-encoded)
        # - signature (hex-encoded; no length prefix)
        def format_field(s):
            return utf8("%d:" % len(s)) + utf8(s)
        to_sign = b"|".join([
            b"2",
            format_field(str(key_version or 0)),
            format_field(timestamp),
            format_field(name),
            format_field(value),
            b''])

        if isinstance(secret, dict):
            assert key_version is not None, 'Key version must be set when sign key dict is used'
            assert version >= 2, 'Version must be at least 2 for key version support'
            secret = secret[key_version]

        signature = _create_signature_v2(secret, to_sign)
        return to_sign + signature
    else:
        raise ValueError("Unsupported version %d" % version)
内部算法-加密
def _decode_signed_value_v1(secret, name, value, max_age_days, clock):
    parts = utf8(value).split(b"|")
    if len(parts) != 3:
        return None
    signature = _create_signature_v1(secret, name, parts[0], parts[1])
    if not _time_independent_equals(parts[2], signature):
        gen_log.warning("Invalid cookie signature %r", value)
        return None
    timestamp = int(parts[1])
    if timestamp < clock() - max_age_days * 86400:
        gen_log.warning("Expired cookie %r", value)
        return None
    if timestamp > clock() + 31 * 86400:
        # _cookie_signature does not hash a delimiter between the
        # parts of the cookie, so an attacker could transfer trailing
        # digits from the payload to the timestamp without altering the
        # signature.  For backwards compatibility, sanity-check timestamp
        # here instead of modifying _cookie_signature.
        gen_log.warning("Cookie timestamp in future; possible tampering %r",
                        value)
        return None
    if parts[1].startswith(b"0"):
        gen_log.warning("Tampered cookie %r", value)
        return None
    try:
        return base64.b64decode(parts[0])
    except Exception:
        return None


def _decode_fields_v2(value):
    def _consume_field(s):
        length, _, rest = s.partition(b':')
        n = int(length)
        field_value = rest[:n]
        # In python 3, indexing bytes returns small integers; we must
        # use a slice to get a byte string as in python 2.
        if rest[n:n + 1] != b'|':
            raise ValueError("malformed v2 signed value field")
        rest = rest[n + 1:]
        return field_value, rest

    rest = value[2:]  # remove version number
    key_version, rest = _consume_field(rest)
    timestamp, rest = _consume_field(rest)
    name_field, rest = _consume_field(rest)
    value_field, passed_sig = _consume_field(rest)
    return int(key_version), timestamp, name_field, value_field, passed_sig


def _decode_signed_value_v2(secret, name, value, max_age_days, clock):
    try:
        key_version, timestamp, name_field, value_field, passed_sig = _decode_fields_v2(value)
    except ValueError:
        return None
    signed_string = value[:-len(passed_sig)]

    if isinstance(secret, dict):
        try:
            secret = secret[key_version]
        except KeyError:
            return None

    expected_sig = _create_signature_v2(secret, signed_string)
    if not _time_independent_equals(passed_sig, expected_sig):
        return None
    if name_field != utf8(name):
        return None
    timestamp = int(timestamp)
    if timestamp < clock() - max_age_days * 86400:
        # The signature has expired.
        return None
    try:
        return base64.b64decode(value_field)
    except Exception:
        return None


def get_signature_key_version(value):
    value = utf8(value)
    version = _get_version(value)
    if version < 2:
        return None
    try:
        key_version, _, _, _, _ = _decode_fields_v2(value)
    except ValueError:
        return None

    return key_version
内部算法-解密

签名Cookie的本质是:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import base64


val = "v1"
r = base64.b64encode(bytes(val, encoding='utf-8'))
print(r)
ret = base64.b64decode(r)
print(ret)

 

写cookie过程:

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

读cookie过程:

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

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

 

#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
import tornado.ioloop
import tornado.web
 
 
class MainHandler(tornado.web.RequestHandler):
 
    def get(self):
        login_user = self.get_secure_cookie("login_user", None)
        if login_user:
            self.write(login_user)
        else:
            self.redirect('/login')
 
 
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 == 'wupeiqi' and password == '123':
            self.set_secure_cookie('login_user', '武沛齐')
            self.redirect('/')
        else:
            self.render('login.html', **{'status': '用户名或密码错误'})
 
settings = {
    'template_path': 'template',
    'static_path': 'static',
    'static_url_prefix': '/static/',
    'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh'
}
 
application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/login", LoginHandler),
], **settings)
 
 
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
Demo-基于cookie进行用户验证
#!/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 == 'wupeiqi' and password == '123':
            self.set_secure_cookie('login_user', '武沛齐')
            self.redirect('/')
        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()
Demo-Toando内部提供基于cookie进行用户验证

4、Ajax上传文件

<!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>
        function UploadFile(){
            var fileObj = document.getElementById("img").files[0];

            var form = new FormData();
            form.append("k1", "v1");
            form.append("fff", fileObj);

            var xhr = new XMLHttpRequest();
            xhr.open("post", '/index', true);
            xhr.send(form);
        }
    </script>
</body>
</html>
Html
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#!/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
var fileObj = $("#img")[0].files[0];
var form = new FormData();
form.append("k1", "v1");
form.append("fff", 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);
    }
})
jQuery Ajax Upload

 

 

 

 

 

 

***** XmlHttpRequest实现Ajax(上)- XmlHttpRequest对象方法和属性的讲解 *****

1、概述
    Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作,该对象在主流浏览器中均存在(除另类的IE),Ajax首次出现IE5.5中存在(ActiveX控件)

2、XmlHttpRequest对象的主要方法
    
    a. void open(String method,String url,Boolen async)
       用于创建请求
       
       参数:
           method: 请求方式(字符串类型),如:POST、GET、DELETE...
           url:    要请求的地址(字符串类型)
           async:  是否异步(布尔类型)

    b. void send(String body)
        用于发送请求

        参数:
            body: 要发送的数据(字符串类型)

    c. void setRequestHeader(String header,String value)
        用于设置请求头

        参数:
            header: 请求头的key(字符串类型)
            vlaue:  请求头的value(字符串类型)

    d. String getAllResponseHeaders()
        获取所有响应头

        返回值:
            响应头数据(字符串类型)

    e. String getResponseHeader(String header)
        获取响应头中指定header的值

        参数:
            header: 响应头的key(字符串类型)

        返回值:
            响应头中指定的header对应的值

    f. void abort()

        终止请求

3、XmlHttpRequest对象的主要属性

    a. Number readyState
       状态值(整数)

       详细:
          0-未初始化,尚未调用open()方法;
          1-启动,调用了open()方法,未调用send()方法;
          2-发送,已经调用了send()方法,未接收到响应;
          3-接收,已经接收到部分响应数据;
          4-完成,已经接收到全部响应数据;

    b. Function onreadystatechange
       当readyState的值改变时自动触发执行其对应的函数(回调函数)

    c. String responseText
       服务器返回的数据(字符串类型)

    d. XmlDocument responseXML
       服务器返回的数据(Xml对象)

    e. Number states
       状态码(整数),如:200、404...

    f. String statesText
       状态文本(字符串),如:OK、NotFound...

{% raw line["username"]%} 原始方式展示

 

分页展示

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Pagenation:
    def __init__(self,current_page,all_item,base_url):
        try:
            page = int(current_page)
        except:
            page = 1
        if page < 1:
            page = 1

        all_pager, c = divmod(all_item, 5)
        if c > 0:
            all_pager += 1

        self.current_page = page
        self.all_pager = all_pager
        self.base_url = base_url

    @property
    def start(self):
        return (self.current_page - 1) * 5

    @property
    def end(self):
        return self.current_page * 5

    def string_pager(self):
        list_page = []
        if self.all_pager < 11:
            s = 1
            t = self.all_pager + 1
        else:  # 总页数大于11
            if self.current_page < 6:
                s = 1
                t = 12
            else:
                if (self.current_page + 5) < self.all_pager:
                    s = self.current_page - 5
                    t = self.current_page + 5 + 1
                else:
                    s = self.all_pager - 11
                    t = self.all_pager + 1
        # 首页
        first = '<a href="/index/1">首页</a>'
        list_page.append(first)
        # 上一页
        # 当前页 page
        if self.current_page == 1:
            prev = '<a href="javascript:void(0);">上一页</a>'
        else:
            prev = '<a href="/index/%s">上一页</a>' % (self.current_page - 1,)
        list_page.append(prev)
        for p in range(s, t):  # 1-11
            if p == self.current_page:
                temp = '<a class="active" href="/index/%s">%s</a>' % (p, p)
            else:
                temp = '<a href="/index/%s">%s</a>' % (p, p)
            list_page.append(temp)
        if self.current_page == self.all_pager:
            nex = '<a href="javascript:void(0);">下一页</a>'
        else:
            nex = '<a href="/index/%s">下一页</a>' % (self.current_page + 1,)

        list_page.append(nex)

        # 尾页
        last = '<a href="/index/%s">尾页</a>' % (self.all_pager,)
        list_page.append(last)

        # 跳转
        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>"""
        list_page.append(jump)
        list_page.append(script)
        str_page = "".join(list_page)
        return str_page
pager
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#!/usr/bin/env python
import tornado.web
from controllers import home
from controllers import buy
from controllers import extend
from controllers import CookieController
settings = {
    'template_path': 'views',  # 模板路径的配置
    'static_path': "statics",  # 静态文件
    "cookie_secret": 'uiuoajskfjalsdjf',
}

# 路由映射,路由系统
application = tornado.web.Application([
    (r"/index/(?P<page>\d*)", home.IndexHandler),
    (r"/extend", extend.IndexHandler, {'k1': 'v1'}),
    (r"/fuck", extend.FuckoffHandler),
    (r"/cookie", CookieController.TestHandler),
    (r"/admin", CookieController.AdminHandler),
    (r"/nomal", CookieController.NomalHandler),
], **settings)

application.add_handlers('buy.wupeiqi.com$',[
    (r"/index/(?P<page>\d*)", buy.IndexHandler),
])

if __name__ == "__main__":
    # socket运行起来
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
start
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.web
from commons import pager
LIST_INFO = [
    {'username': 'alex', "email": "alex3721@163.com"},
]
for i in range(300):
    temp = {'username': 'alex'+str(i), "email": str(i) + '123@qq.com'}
    LIST_INFO.append(temp)

class IndexHandler(tornado.web.RequestHandler):

    def get(self, page):
        obj = pager.Pagenation(page, len(LIST_INFO), '/index/')
        current_list = LIST_INFO[obj.start:obj.end]
        str_page = obj.string_pager()
        self.render('home/index.html', list_info = current_list, current_page = obj.current_page, str_page = str_page)

    def post(self,page):
        user = self.get_argument('username')
        email = self.get_argument('email')
        temp = {'username': user, 'email': email}
        LIST_INFO.append(temp)
        self.redirect("/index/"+page)
home
<!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: cadetblue;
        }
        .pager a.active{
            background-color: brown;
            color: white;
        }
    </style>
</head>
<body>
    <h1>提交数据</h1>
    <form method="post" action="/index/{{current_page}}">
        <input name="username" type="text" />
        <input name="email" type="text" />
        <input type="submit" value="提交" />
    </form>
    <h1>显示数据</h1>
    <table border="1">
        <thead>
            <tr>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
        </thead>
        <tbody>
            {% for line in list_info %}
                <tr>
                    <!--<td>{{line['username']}}</td>-->
                    <td>{{ line['username'] }}</td>
                    <td>{{line['email']}}</td>
                </tr>
            {% end %}
        </tbody>
    </table>
    <div class="pager">
        {% raw str_page %}
    </div>
</body>
</html>
index

 

每次运行自动执行,tornado.web.RequestHandler 里面有自动执行

class MainHandler(tornado.web.RequestHandler):
def initialize(self):

xss攻击 给浏览器注入脚本

 

 

作业:

self.redirect("/index") 刷新页面
window.location.reload() 刷新当前页面


二、表单验证

在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

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

#!/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

上课代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import re
import os

class IPFiled:
    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_dict=None, required=True):
        # 封装了错误信息
        self.error_dict = {}
        if error_dict:
            self.error_dict.update(error_dict)

        self.required = required

        self.error = None # 错误信息
        self.value = None
        self.is_valid = False

    def validate(self, name, input_value):
        """
        :param name: 字段名
        :param input_value: 用户表单中输入的内容
        :return:
        """
        if not self.required:
            # 用户输入可以为空
            self.is_valid = True
            self.value = input_value
        else:
            if not input_value.strip():
                if self.error_dict.get('required',None):
                    self.error = self.error_dict['required']
                else:
                    self.error = "%s is required" % name
            else:
                ret = re.match(IPFiled.REGULAR, input_value)
                if ret:
                    self.is_valid = True
                    self.value = input_value
                else:
                    if self.error_dict.get('valid', None):
                        self.error = self.error_dict['valid']
                    else:
                        self.error = "%s is invalid" % name

class StringFiled:
    REGULAR = "^(.*)$"

    def __init__(self, error_dict=None, required=True):
        # 封装了错误信息
        self.error_dict = {}
        if error_dict:
            self.error_dict.update(error_dict)

        self.required = required

        self.error = None # 错误信息
        self.value = None
        self.is_valid = False

    def validate(self, name, input_value):
        """
        :param name: 字段名
        :param input_value: 用户表单中输入的内容
        :return:
        """
        if not self.required:
            # 用户输入可以为空
            self.is_valid = True
            self.value = input_value
        else:
            if not input_value.strip():
                if self.error_dict.get('required',None):
                    self.error = self.error_dict['required']
                else:
                    self.error = "%s is required" % name
            else:
                ret = re.match(IPFiled.REGULAR, input_value)
                if ret:
                    self.is_valid = True
                    self.value = input_value
                else:
                    if self.error_dict.get('valid', None):
                        self.error = self.error_dict['valid']
                    else:
                        self.error = "%s is invalid" % name

class ChechBoxFiled:

    def __init__(self, error_dict=None, required=True):
        # 封装了错误信息
        self.error_dict = {}
        if error_dict:
            self.error_dict.update(error_dict)

        self.required = required

        self.error = None # 错误信息
        self.value = None
        self.is_valid = False

    def validate(self, name, input_value):
        """
        :param name: 字段名 favor
        :param input_value: 用户表单中输入的内容,列表None, [1,2]
        :return:
        """

        if not self.required:
            # 用户输入可以为空
            self.is_valid = True
            self.value = input_value
        else:
            if not input_value:
                if self.error_dict.get('required',None):
                    self.error = self.error_dict['required']
                else:
                    self.error = "%s is required" % name
            else:
                self.is_valid = True
                self.value = input_value

class FileFiled:

    REGULAR = "^(\w+\.pdf)|(\w+\.mp3)|(\w+\.py)$"

    def __init__(self, error_dict=None, required=True):
        # 封装了错误信息
        self.error_dict = {}
        if error_dict:
            self.error_dict.update(error_dict)

        self.required = required

        self.error = None  # 错误信息
        self.value = []
        self.is_valid = True
        self.name = None
        self.success_file_name_list = []

    def validate(self, name, all_file_name_list):
        """
        :param name: 字段名
        :param all_file_name_list: 所有文件文件名
        :return:
        """
        self.name = name
        if not self.required:
            # 用户输入可以为空
            self.is_valid = True
            self.value = all_file_name_list
        else:
            if not all_file_name_list:
                self.is_valid = False
                if self.error_dict.get('required',None):
                    self.error = self.error_dict['required']
                else:
                    self.error = "%s is required" % name
            else:
                # 循环所有的文件名
                for file_name in all_file_name_list:
                    ret = re.match(FileFiled.REGULAR, file_name)
                    if not ret:
                        self.is_valid = False
                        if self.error_dict.get('valid', None):
                            self.error = self.error_dict['valid']
                        else:
                            self.error = "%s is invalid" % name
                        break
                    else:
                        self.value.append(file_name)

    def save(self, request, path='statics'):
        # 所有文件列表
        file_metas = request.files.get(self.name)
        # 循环文件列表
        temp_list = []
        for meta in file_metas:
            # 每一个文件的文件名
            file_name = meta['filename']
            # self.value:[1.py, 2.py]  【statics/1.py  statics/2.py】
            new_file_name = os.path.join(path, file_name)
            if file_name and file_name in self.value:
                temp_list.append(new_file_name)
                with open(new_file_name, 'wb') as up:
                    up.write(meta['body'])
        self.value = temp_list
class BaseForm:
    def check_valid(self, handle):
        flag = True
        error_message_dict = {}
        success_value_dict = {}
        for key, regular in self.__dict__.items():
            # key: ip .....
            # handle: HomeIndex对象,self.get_... self.
            # regular: IPFiled(required=True)

            if type(regular) == ChechBoxFiled:
                input_value = handle.get_arguments(key)
            elif type(regular) == FileFiled:
                # 获取文件名
                file_list = handle.request.files.get(key)
                # [{'body':'xx','filename':'xx'},{'body':'xx','filename':'xx'}]
                input_value = []
                for item in file_list:
                    input_value.append(item['filename'])
                # 所有文件名进行验证
            else:
                input_value = handle.get_argument(key)
            # input_value = 用户输入的值
            # 将具体的验证,放在IPFiled对象中
            regular.validate(key, input_value)

            if regular.is_valid:
                success_value_dict[key] = regular.value
            else:
                error_message_dict[key] = regular.error
                flag = False

        return flag, success_value_dict, error_message_dict

class HomeForm(BaseForm):
    def __init__(self):
        self.ip = IPFiled(required=True, error_dict={'required': "别闹,别整空的..", "valid": "骚年,格式错误了"})
        self.host = StringFiled(required=False)
        self.favor = ChechBoxFiled(required=True)
        self.fafafa = FileFiled(required=True)

class HomeHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('home.html', error_dict=None)

    def post(self, *args, **kwargs):

        # self.get_argument()
        # self.get_arguments()
        # files = self.request.files.get('fafafa',[])
        # # files = [ 文件一、文件二]
        # print(type(files),files)

        obj = HomeForm()
        is_valid, success_dict, error_dict = obj.check_valid(self)
        if is_valid:
            print('success',success_dict)
            obj.fafafa.save(self.request)
        else:
            print('error', error_dict)
            self.render('home.html', error_dict=error_dict)

settings = {
    'template_path': 'views',
    'static_path': 'statics',
    'static_url_prefix': '/statics/',
}

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


if __name__ == "__main__":
    application.listen(8001)
    tornado.ioloop.IOLoop.instance().start()
app
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/home" method="post" enctype="multipart/form-data">

        <input type="text" name="ip" placeholder="ip"/>
        <input type="text" name="host" placeholder="host"/>

        <p>
            <input type="checkbox" name="favor" value="1" /> 篮球;
            <input type="checkbox" name="favor" value="2" /> 足球;
            <input type="checkbox" name="favor" value="3" /> 玻璃球;
        </p>
        <p>
            <input type="file" name="fafafa" />
            <input type="file" name="fafafa" />
        </p>

        {% if error_dict and 'ip' in error_dict %}
        <span>{{error_dict['ip']}}</span>
        {% end %}
        <input type="submit" />
    </form>
</body>
</html>
home.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/index" method="post">
        <input type="text" name="host" placeholder="host" />
        <input type="text" name="ip" placeholder="ip"/>
        <input type="text" name="port" placeholder="port"/>
        <input type="text" name="phone" placeholder="phone" />
        <input type="submit" />
    </form>
</body>
</html>
index.html

 

 

 

 

 

 



 

posted @ 2016-07-24 07:31  若时光搁浅  阅读(333)  评论(0)    收藏  举报