首页 > 代码库 > Tornado

Tornado

Web框架之Tornado

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

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

下载安装:

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

框架使用

一、快速上手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
# -*- coding:utf-8 -*-
    
import tornado.ioloop
import tornado.web
    
    
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
    
application = tornado.web.Application([
    (r"/index", MainHandler),
])
    
    
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

执行过程:

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

二、路由系统

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env python
# -*- coding:utf-8 -*-
    
import tornado.ioloop
import tornado.web
    
    
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
    
class StoryHandler(tornado.web.RequestHandler):
    def get(self, story_id):
        self.write("You requested the story " + story_id)
    
class BuyHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("buy.wupeiqi.com/index")
    
application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/story/([0-9]+)", StoryHandler),
])
    
application.add_handlers(‘buy.wupeiqi.com$‘, [
    (r‘/index‘,BuyHandler),
])
    
if __name__ == "__main__":
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()

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

技术分享

三、模板引擎

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

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

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

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

1、基本使用

技术分享 app.py
技术分享 index.html
技术分享 其他方法

2、母版

技术分享 layout.html
技术分享 index.html

3、导入

技术分享 header.html
技术分享 index.html

4、自定义UIMethod以UIModule

a. 定义

技术分享 uimethods.py
技术分享 uimodules.py

b. 注册

技术分享 View Code

c. 使用

技术分享 View Code

四、静态文件

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

技术分享 app.py
技术分享 index.html

注:静态文件缓存的实现

技术分享 View Code

五、cookie

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

1、基本操作

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

2、加密cookie(签名)

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

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

签名Cookie的本质是:

写cookie过程:

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

读cookie过程:

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

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

技术分享 基于Cookie实现用户验证-Demo
技术分享 基于签名Cookie实现用户验证-Demo

3、JavaScript操作Cookie

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

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

对于参数:

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

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

六、CSRF

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

技术分享 配置
技术分享 普通表单
技术分享 使用 - AJAX

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

七、上传文件

1、Form表单上传

技术分享 HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
import tornado.ioloop
import tornado.web
 
 
class MainHandler(tornado.web.RequestHandler):
    def get(self):
 
        self.render(‘index.html‘)
 
    def post(self*args, **kwargs):
        file_metas = self.request.files["fff"]
        # print(file_metas)
        for meta in file_metas:
            file_name = meta[‘filename‘]
            with open(file_name,‘wb‘) as up:
                up.write(meta[‘body‘])
 
settings = {
    ‘template_path‘‘template‘,
}
 
application = tornado.web.Application([
    (r"/index", MainHandler),
], **settings)
 
 
if __name__ == "__main__":
    application.listen(8000)
    tornado.ioloop.IOLoop.instance().start()
 
Python

 2、AJAX上传

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

八、验证码

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

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

示例截图:技术分享

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

自定义Web组件

一、Session

1、面向对象基础

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

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

2、Tornado扩展

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

class BaseHandler(tornado.web.RequestHandler):       def initialize(self):        self.xxoo = "wupeiqi"      class MainHandler(BaseHandler):       def get(self):        print(self.xxoo)        self.write(‘index‘) class IndexHandler(BaseHandler):       def get(self):        print(self.xxoo)        self.write(‘index‘)

3、session

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

技术分享 自定义Session

4、分布式Session

技术分享 一致性哈西
技术分享 session

二、表单验证

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

技术分享 HTML
技术分享 Python

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

技术分享 View Code

 

 

 

 

 

 
分类: tornado源码系列, python基础到高级

Tornado