一 Tornado概述

Tornado是FriendFeed使用的可扩展的非阻塞式web框架及其相关工具的开源版本。这个Web框架看起来有些像web.py或者Google的 webapp,不过为了能有效利用非阻塞式服务器环境,这个Web框架还包含了一些相关的有用工具和优化。
   Tornado和现在的主流Web服务器框架(包括大多数Python的框架)有着明显的区别:它是非阻塞式服务器框架,而且速度相当快。由于其非阻塞的方式和对epoll的运用,Tornado每秒可以处理数以千计的连接,这意味着对于实时Web服务来说,Tornado是一个理想的Web框架。开发这个Web框架的主要目的是为了处理FriendFeed的实时功能——在FriendFeed的应用里每一个活动用户都会保持着一个服务器连接(关于如何扩容服务器,以处理数以千计的客户端的连接的问题,请参阅C10K问题),同时Tornado是轻量级的web框架,它主要解决了性能问题,让开发者可以灵活的去扩展相关组件。

                                                          C10K问题

    基于线程的服务器,如Apache,为了传入的连接,维护了一个操作系统的线程池。Apache会为每个HTTP连接分配线程池中的一个线程,如果所有的线程都处于被占用的状态并且尚有内存可用时,则生成一个新的线程。尽管不同的操作系统会有不同的设置,大多数Linux发布版中都是默认线程堆大小为8MB。Apache的架构在大负载下变得不可预测,为每个打开的连接维护一个大的线程池等待数据极易迅速耗光服务器的内存资源。

   大多数社交网络应用都会展示实时更新来提醒新消息、状态变化以及用户通知,这就要求客户端需要保持一个打开的连接来等待服务器端的任何响应。这些长连接或推送请求使得Apache的最大线程池迅速饱和。一旦线程池的资源耗尽,服务器将不能再响应新的请求。

   异步服务器在这一场景中的应用相对较新,但他们正是被设计用来减轻基于线程的服务器的限制的。当负载增加时,诸如Node.js,lighttpd和Tornodo这样的服务器使用协作的多任务的方式进行优雅的扩展。也就是说,如果当前请求正在等待来自其他资源的数据(比如数据库查询或HTTP请求)时,一个异步服务器可以明确地控制以挂起请求。异步服务器用来恢复暂停的操作的一个常见模式是当合适的数据准备好时调用回调函数。

二  Tornado使用入门

1 安装

pip安装

pip install tornado
源码安装

https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz

python setup.py install

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()
第1步:执行脚本,监听8888端口;
第2步:浏览器客户端访问/index --> http://127.0.0.1:8888/index;
第3步:服务器接受请求,并交由对应的类处理该请求;
第4步:类接收到请求之后,根据请求方式(post/get/delete ...)的不同调用并执行相应的方法;
第5步:对应方法返回的字符串内容发送到浏览器;

3 路由系统

Tornado中,路由系统其实就是url和类的对应关系,而其他web框架,很多均是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()

4 模板

Tornado中的模板语言与django类似,模板引擎先将模板文件加载到内存,然后将模板文件与数据进行混合,最终获取到一个完整的字符串,最后将字符串返回给请求者。
   Tornado的模板语言支持"控制语句"和"表达语句",控制语句是使用{%  %}包起来的,例如{% if len(items) > 2 %}。表达语句是使用{{ xx }}包起来的,例如{{ items[0] }}。
   控制语句和对应的Python语句的格式基本完全相同。支持if、for、while和try,这些语句逻辑结束的位置需要用 {% end %} 做标记。还通过extends和block语句来实现模板的继承。这些在template模块的代码文档中有着详细的描述。

tornado程序主文件

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

layout.html文件(母板)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
{% block css%} {% end %}
</head>
<body>
<div><h1>TEST</h1></div>
{% block htmlbody %}{% end %}
<script src="{{static_url('js/jquery-1.8.2.min.js')}}"></script>
{% block JavaScript %}{% end %}
</body>
</html>

index.html文件(子板)

{% extends 'layout.html' %}

{% block css %}
<link href="{{static_url('css/index.css')}}" rel="stylesheet" />
{% end %} {% block htmlbody %}
<h1 id="test_id" class="tim">Tornado模板.</h1>
{% end %} {% block JavaScript %} {% end %}

模板中for循环的语法

{% 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 %}
在模板中默认提供了一些函数、字段、类以供模板使用:
    escape: tornado.escape.xhtml_escape的別名
    xhtml_escape: tornado.escape.xhtml_escape的別名
    url_escape: tornado.escape.url_escape的別名
    json_encode: tornado.escape.json_encode的別名
    squeeze: tornado.escape.squeeze的別名
    linkify: tornado.escape.linkify的別名
    datetime: Python 的 datetime模组
    handler: 当前的 RequestHandler对象
    request: handler.request的別名
    current_user: handler.current_user的別名
    locale: handler.locale的別名
    _: handler.locale.translate的別名
    static_url: for handler.static_url的別名
    xsrf_form_html: handler.xsrf_form_html的別名

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

# uimethods.py
def tab(self):
return 'UIMethod'
#uimodule.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>')

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

(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>

5 实用功能

(1)静态文件

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

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

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

静态文件的配置:

静态文件的配置

<link href="{{static_url('css/index.css')}}" rel="stylesheet" />
    这里的路径写成变量static_url的形式,是方便更改维护静态文件的路径,这点与Django是一致的,

同时这种写法在Tornado中还有另外一个功能,即起到缓存的作用。

缓存作用的解释:

对于静态文件/static/commons.js,如果前端使用static_url配置路径后,则类似于在url的后面加了

一串字符串,即/static/commons.js?v=asdf123,那么当浏览器访问时会携带这个特殊的字符串,如果发现

客户端缓存的静态文件没变,则直接渲染前端页面就行,不必再去服务端重新加载页面,加快了访问的速度。

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)CSRF

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

配置python代码

settings = {
"xsrf_cookies": True,
}
application = tornado.web.Application([
(r"/", MainHandler),
(r"/login", LoginHandler),
], **settings)

form表单提交

<form action="/new_message" method="post">
{{ xsrf_form_html() }}
<input type="text" name="message"/>
<input type="submit" value="Post"/>
</form>

Ajax操作

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

参考资料:

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

python web框架——初识tornado的更多相关文章

  1. python web框架之Tornado的简单使用

    python web框架有很多,比如常用的有django,flask等.今天主要介绍Tornado ,Tornado是一个用Python写的相对简单的.不设障碍的Web服务器架构,用以处理上万的同时的 ...

  2. python web框架之Tornado

    说Tornado之前分享几个前端不错的网站: -- Bootstrap http://www.bootcss.com/ -- Font Awesome http://fontawesome.io/ - ...

  3. Python Web 框架:Tornado

    1.Tornado Tornado:python编写的web服务器兼web应用框架 1.1.Tornado的优势 轻量级web框架 异步非阻塞IO处理方式 出色的抗负载能力 优异的处理性能,不依赖多进 ...

  4. 浅谈Python web框架

    一.Python web框架 Web Framework,Ruby的世界Rails一统江湖,而Python则是一个百花齐放的世界,各种micro-framework.framework不可胜数,不完全 ...

  5. python web框架——扩展Django&tornado

    一 Django自定义分页 目的:自定义分页功能,并把它写成模块(注意其中涉及到的python基础知识) models.py文件 # Create your models here. class Us ...

  6. 异步非阻塞IO的Python Web框架--Tornado

    Tornado的全称是Torado Web Server,从名字上就可知它可用作Web服务器,但同时它也是一个Python Web的开发框架.最初是在FriendFeed公司的网站上使用,FaceBo ...

  7. Python Web框架 tornado 异步原理

    Python Web框架 tornado 异步原理 参考:http://www.jb51.net/article/64747.htm 待整理

  8. Python web框架——Tornado

    Tornado是一个Python Web框架和异步网络库,最初由FriendFeed开发.通过使用非阻塞网络I / O,Tornado可以扩展到数万个开放连接,使其成为需要长时间连接每个用户的长轮询, ...

  9. Python web框架 Tornado(二)异步非阻塞

    异步非阻塞 阻塞式:(适用于所有框架,Django,Flask,Tornado,Bottle) 一个请求到来未处理完成,后续一直等待 解决方案:多线程,多进程 异步非阻塞(存在IO请求): Torna ...

随机推荐

  1. 【洛谷P1941】飞扬的小鸟

    f [ i ] [ j ] 表示横坐标为 i ,高度为 j 时的最小点击次数 分别dp处理: 1.上升,(1)<m (2)>=m 2.下降 3.管道 #include<cstdio& ...

  2. php安装gearman扩展实现异步分步式任务

    参考: 1.小喵爱你的博客 2.PHP Manual 依赖 1.gcc44 2.boost >=1.39 3.libevent 4.php5.3+ 5.update ld.so.conf 安装依 ...

  3. RMQ_ST算法

    RMQ (Range Minimum/Maximum Query)算法 1. 概述 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数 ...

  4. [Leetcode][JAVA] Triangled

    Triangle Given a triangle, find the minimum path sum from top to bottom. Each step you may move to a ...

  5. 4.2.2 网络编程之Socket

    1基于TCP协议的Socket 服务器端首先声明一个ServerSocket对象并且指定端口号,然后调用Serversocket的accept()方法接收客户端的数据.Accept()方法在没有数据进 ...

  6. as的一些常见问题

    assets文件的存放目录在”src/main/”目录下,和java.res文件夹平级: aidl文件需要单独在”src/main/”目录下新建一个文件夹,然后创建对应的包名,将aidl文件放在包名对 ...

  7. Yaf零基础学习总结1-Yaf框架简介

    从今天开始,给大家讲解下yaf框架,讲解之前肯定要了解下yaf是个什么东西,当然,从标题我们已经知道yaf是个PHP框架了,也许大家对于PHP框架并不陌生,一般PHP程序员用过的框架至少有一两个吧,国 ...

  8. 第六天:用javascript实现购彩拆分票的计算奖金

    需求如下: 购彩金额  拆分票数  <= 10    1票<= 100    10票<= 200   20票<= 500   50票<= 1000   100票 中奖金额 ...

  9. PropertyChangedCallback 只触发了一次?

    在自定义的用户控件中,添加一个依赖属性,如下: public static readonly DependencyProperty ItemsSourceProperty = DependencyPr ...

  10. WebApi与手机客户端通信安全机制

    最近公司有几个项目需要开发手机客户端,服务器端选用WebApi,那么如何保证手机客户端在请求服务器端时数据不被篡改,如何保证一个http请求的失效机制,下面总结一下我们在项目中针对这两个问题的解决方案 ...