一 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. 简单介绍Android应用特色及详解四大组件

    Android应用特色 Android主要有什么特色呢,有以下几个方面来体现: 四大组件 丰富的系统控件 SQLite数据库等持久化技术 地理位置定位 强大的多媒体 传感器 1,四大组件 Androi ...

  2. c#:未将对象引用设置到对象的实例--可能出现的问题总结(转)

    1.c#:未将对象引用设置到对象的实例--可能出现的问题总结(转):http://www.cnblogs.com/KeenLeung/archive/2013/06/23/3150578.html

  3. jsp学习---使用jsp和JavaBean实现超简单网页计算器

    一.需求 如题,用jsp实现一个超简单的网页计算器. 二.实现 1.效果图 1)初始界面: 2)随便输入两个数进行相乘: 3)当除数为零时提示报错: 2.代码 Calculator.java pack ...

  4. Awesome Machine Learning

    https://github.com/josephmisiti/awesome-machine-learning 包含了很多的machine-learning开源的资源,包括各种语言的machin l ...

  5. aceAdmin fuelux tree 从后台获取数据,并设置节点ID等属性

    如题,从后台封装数据,有两种方式渲染节点的数据: 1.全部节点加载 2.根据父节点加载子节点 首先,先介绍下第一种渲染方式: 后台返回数据格式(所有的附加属性,都可放在additionalParame ...

  6. Browser设置搜索引擎

    Browser设置搜索引擎,在com.android.browser.preferences.GeneralPreferencesFragment中加载R.xml.general_preference ...

  7. Django跑起来

    1.  安装python 2.  安装pip 3.  安装dj 4.  配置dj 5.  建立dj  web app 6.  开始项目 打算写这篇文章,先把目录写上

  8. POJ3680_Intervals

    给你若干个区间,每个区间有一个权值,你可以选出某些区间,使得在保证没有任何一段的覆盖次数超过k的前提下,总的权值最大. 这个建模真的十分神奇,赞一个. 对于给出的每一个区间,离散化,最终我们可以知道所 ...

  9. 解决Failed to load class "org.slf4j.impl.StaticLoggerBinder"

    Hibernate使用SLF4J API记录日志,所以在Hibernate的lib中,不再提供Log4J的包,而大部分框架依然使用Log4J记录日志,这样导致了兼容性问题. 解决办法,两步: 一.在编 ...

  10. 1296: [SCOI2009]粉刷匠

    Description windy有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色. 每个 ...