首页 > 其他 > 详细

Tornado框架

时间:2016-08-02 13:35:40      阅读:121      评论:0      收藏:0      [点我收藏+]

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")
  
application = tornado.web.Application([
    (r"/index", MainHandler),
])
  
  
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

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

准备阶段

  加载配置文件

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

  创建socket  

循环阶段

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

流程:

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

  

 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

 

路由系统可以分为几类:

  • 静态路由

  • 动态路由

  • 请求方法路由

  • 二级路由

2.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.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)
正则例子

2.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

 

2.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):
        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()
主文件lndex.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) #如果变量不存在时,为变量设置默认值

    

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

  • 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代码会被执行,从而达到恶意攻击用户的特殊目的。

 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再来发送请求

 

4、Cookie

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

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

 

b、签名

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

 

签名Cookie的本质是:

写cookie过程:

  • 将值进行base64加密

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

  • 拼接 签名 + 加密值

读cookie过程:

  • 读取 签名 + 加密值

  • 对签名进行验证

  • base64解密,获取值内容

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

 

 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、Session

1.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

  

2、表单验证

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

 

 

 

 

 

上面实例的源码文件夹: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

Tornado框架

原文:http://www.cnblogs.com/kongqi816-boke/p/5699866.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!