Tornado(一)

Tornado 特点

Tornado是一个用Python写的相对简单的、不设障碍的Web服务器架构,用以处理上万的同时的连接口,让实时的Web服务通畅起来。虽然跟现在的一些用Python写的Web架构相似,比如Django,但Tornado更注重速度,能够处理海量的同时发生的流量。 
FriendFeed的联合创始人Bret Taylor的博客里介绍了更多,他说:把Tornado开源,FriendFeed和Facebook期望第三方能够用以建筑实时的Web服务。其具体的工作原理如上图,看起来很像是FriendFeed的评论系统。 

Taylor认为Tornado的三个关键部分是: 
         完整的用以构建网站的基础模块。Tornado包含内置的用以解决网络开发最难和最烦的功能模块,包括模板、signed cookies、用户认证、地方化(localization)、aggressive static file caching, cross-site request forgery protection,以及类似Facebook Connect的第三方认证。开发者可以随取所需,并且自由组合,甚至把Tornado与其他架构组合。 
实时服务。Tornado支持大量的同时发生的信息连接。用Tornado,能够通过HTTP或者Long Polling方便的书写实时服务。要知道,每一个FriendFeed的活跃用户都保持有一个连通FriendFeed服务器的开放通路。 
高效能。Tornado比大多数用Python写的Web架构更快。根据一些实验,Tornado的速度是一般架构的4倍。

 

  Tornado 支持二种模式 一种是串行访问处理,异步非阻塞。当客户端访问web,tornado 可以自行定义前面2个的处理方式。天生支持RESTful

  安装

  pip install tornado

  官方:http://www.tornadoweb.org/en/stable/

 

 

一 、HELLO word 

 1 import tornado.ioloop
 2 import tornado.web
 3 
 4 class MainHandler(tornado.web.RequestHandler):
 5     def get(self):
 6         self.write("Hello, world")
 7 
 8 def make_app():
 9     return tornado.web.Application([
10         (r"/index", MainHandler),
11     ])
12 
13 if __name__ == "__main__":
14     app = make_app()
15     app.listen(8888)
16     tornado.ioloop.IOLoop.current().start()

访问 ip:8888/index 测试内容

 

 

配置模板

返回html页面

#_*_coding:utf-8_*_
import tornado.ioloop
import tornado.web#通过字典定义的方式定义配置文件属性,
settings = {'template_path':'template',
}class MainHandler(tornado.web.RequestHandler):def get(self):#self.write("Hello, world")#返回模板中的页面self.render('index.html')def make_app():#把setting这个配置参数带入到方法中return tornado.web.Application([(r"/index", MainHandler),],**settings)if __name__ == "__main__":app = make_app()app.listen(8888)tornado.ioloop.IOLoop.current().start()

然后就可以测试页面了,非常的简单

这里介绍render都做了什么
class MainHandler(tornado.web.RequestHandler):
               def get(self):

                             1先找到template的路径

                             2根据路径找到对应的html页面(拼接)

                             3python open方法读取这个html页面内容,将内容读取到了内存中。实际上读出来的其实就是一个字符串

                             4 self.write(open('html').read()) 读出这个文件然后写回(self.write方法)

                             5self.write用socket的send方法,将字符串发送给客户端用户(这里会将这个字符串塞进一个双向队列里面,send方法回去队列中去数据然后发送给客户端),用户就可以看见web页面了(这个就是一个简单的过程)

                             dic ={ 'name'='aaaa' }

                              这里在说一下模板渲染,上面定义了一个字典dic。那过程就需要多加一步了。

                             在上面4步:

                                     4open('html').read() 先把文件读取出来

                                     5渲染html页面(实际就是一个很长的字符串),替换字符串中的特殊模板语言(在html文件中也会有模板语言{{ name }},这个key可以dic中的key对应上)

                                     6self.write 

                      self.render('index.html')

                      #self.render('index.html',**dic)  渲染必须将字典当参数一起传递

 

 

路由系统

#_*_coding:utf-8_*_
import tornado.ioloop
import tornado.web#通过字典定义的方式定义配置文件属性,
settings = {'template_path':'template',
}class MainHandler(tornado.web.RequestHandler):def get(self):dic={'name':'abc'}self.render('index.html',**dic)class Home(tornado.web.RequestHandler):def get(self):self.render('home.html')class news(tornado.web.RequestHandler):#接受从url传递过来的参数,nid是从url中传递过来的def get(self,nid):self.write(str(nid))
'''(r"/news/(\d+)",news),这里也可以用正则匹配.想要当参数传递必须()中写表达式
'''
def make_app():#把setting这个配置参数带入到方法中return tornado.web.Application([(r"/index", MainHandler),(r"/home",Home),(r"/news/(\d+)",news),],**settings)if __name__ == "__main__":app = make_app()app.listen(8888)tornado.ioloop.IOLoop.current().start()

 

匹配二级域名,这个是Tornado独有的,一般都是匹配xxx.xxxx.xxx/后面的参数,现在要匹配 psp.xxx.com/index  ,匹配psp 这个前缀

#_*_coding:utf-8_*_
import tornado.ioloop
import tornado.web#通过字典定义的方式定义配置文件属性,
settings = {'template_path':'template',
}class MainHandler(tornado.web.RequestHandler):def get(self):dic={'name':'abc'}self.render('index.html',**dic)class psphandler(tornado.web.RequestHandler):def get(self):self.write("psp.tb.com/index")
app=tornado.web.Application([(r"/index", MainHandler),],**settings)#对app的add_handlers方法在增加一个匹配项,如果匹配上就掉对应的方法。当url过来的时候如果psp.tb.com匹配不上还是回去其它定义的规则中继续匹配
app.add_handlers('psp.tb.com',[(r"/index",psphandler),
])if __name__ == "__main__":app.listen(8888)tornado.ioloop.IOLoop.current().start()

测试结果:

路由psp

 路由正常规则

 

 

静态文件

 

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link href="{{static_url("commons.css")}}" rel="stylesheet" />
</head>
<body>
<h1>index.html</h1>
<h1>{{ name }}</h1>
</body>
</html>
index.html
 1 #_*_coding:utf-8_*_
 2 import tornado.ioloop
 3 import tornado.web
 4 
 5 '''
 6 必须定义'static_path':'static',否则'static_path_prefix':'/static/',会报错误。
 7 现在不定义'static_path_prefix':'/static/',前端html文件"{{static_url("commons.css")}}"  也会对文件添加md5码。
 8 当文件更新的时候就会非常方便了,客户端也可以发现静态文件更新,再也不用手动强制更新ie缓存了
 9 '''
10 settings = {
11     'template_path':'template',
12     'static_path':'static',
13     'static_path_prefix':'/static/',
14 }
15 
16 class MainHandler(tornado.web.RequestHandler):
17     def get(self):
18         dic={
19             'name':'abc'
20         }
21         self.render('index.html',**dic)
22 app=tornado.web.Application([
23         (r"/index", MainHandler),
24     ],**settings)
25 
26 if __name__ == "__main__":
27     app.listen(8888)
28     tornado.ioloop.IOLoop.current().start()

访问展示:

主要看静态文件后面的自己生成的md5值,然后自己改一下样式重启服务器,客户端刷新就会直接刷新缓存了。

这里还有一个好处是前端不用管后端static文件夹的改变,后端更改路径不会影响前端

 

 

cookie操作

#_*_coding:utf-8_*_
import tornado.ioloop
import tornado.web#cookie_secret这个配置的是加"盐"的值
settings = {'template_path':'template','static_path':'static','static_path_prefix':'/static/','cookie_secret':'asdasdasda',}
class HomeHandler(tornado.web.RequestHandler):def get(self):#读取客户端cookie,k1就是客户端cookie的一个字符串#self.set_cookie('k1')#设置cookie (参数):name, value, domain=None, expires=None, path="/",expires_days=None, **kwargs#path="/" 这个参数是设置cookie的作用域范围。www.xxx.com/home 如果这样写就说明这个cookie只作用在home这个url上别的url无法使用#set_cookie是不加密的 直接明文就传递给客户端,可以用调试工具查看到self.set_cookie('name','abc')#加密cookie 进行签名#self.set_secure_cookie('name','123')self.render('home.html')def make_app():return tornado.web.Application([(r"/home", HomeHandler),],**settings)if __name__ == "__main__":app = make_app()app.listen(8888)tornado.ioloop.IOLoop.current().start()

演示:

因为这里无法同时开启self.set_cookie和self.set_secure_cookie。所以这个实验是执行完一个在换另一个。加密的还是相对比较安全的 。

 

看源码是如何处理加密:

源码:

def set_secure_cookie(self, name, value, expires_days=30, version=None,**kwargs):# 这里默认将超时时间设置了expires_days=30,注意看它这直接调用了不加密码的cookie方法self.set_cookie()。
#self.create_signed_value(name, value,ersion=version)加密方法
self.set_cookie(name, self.create_signed_value(name, value,ersion=version),xpires_days=expires_days, **kwargs)

create_signed_value加密方法

def create_signed_value(self, name, value, version=None):#获取加盐的方法self.require_setting("cookie_secret", "secure cookies")#在前面的setting增加这几个key就可以self.require_setting("cookie_secret", "secure cookies")secret = self.application.settings["cookie_secret"]key_version = Noneif isinstance(secret, dict):if self.application.settings.get("key_version") is None:raise Exception("key_version setting must be used for secret_key dicts")key_version = self.application.settings["key_version"]#这个是全局的变量,虽然跟这个类中的方法名字相同。但是这个不是传给自己的   create_signed_valuereturn create_signed_value(secret, name, value, version=version,key_version=key_version)
create_signed_value
def create_signed_value(secret, name, value, version=None, clock=None,key_version=None):if version is None:version = DEFAULT_SIGNED_VALUE_VERSIONif clock is None:clock = time.time#生成时间戳timestamp = utf8(str(int(clock())))#用base64.b64encode加密,base64是可以反解回来的value = base64.b64encode(utf8(value))#有2个版本加密一个是v1一个v2if version == 1:signature = _create_signature_v1(secret, name, value, timestamp)value = b"|".join([value, timestamp, signature])return valueelif 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 + signatureelse:raise ValueError("Unsupported version %d" % version)
全局create_signed_value
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())
加密V1和V2

这样做比较安全,当黑客如果知道你的加密过程伪造cookie,Tornado会根据它的cookie先去做签名,如果签名跟服务器上的一致那么就OK。但是这里有一个重要的因素是 

secret = self.application.settings["cookie_secret"]  这个值是定在服务器这边的 很难获取到。如果这值知道了那么久没有任何办法了。

反解过程可以看self.get_secure_cookie() 过程都在这里面了。 

 

转载于:https://www.cnblogs.com/menkeyi/p/5961103.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372208.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android下Opengl ES实现单屏幕双眼显示

http://blog.csdn.net/u011371324/article/details/68946779 默认情况下&#xff0c;Opengl ES使用系统提供的帧缓冲区作为绘图表面&#xff0c;一般情况下&#xff0c;如果只在屏幕的表面绘图的话&#xff0c;系统提供的默认帧缓冲区很高效&#xff0c;但是很多应用程序需要渲…

Oracle Service Bus –线程阻塞案例研究

本案例研究描述了在AIX 6.1和IBM Java VM 1.6上运行的Oracle Service Bus 11g遇到的线程阻塞问题的完整根本原因分析过程。 本文也是您提高线程转储分析技能的绝佳机会&#xff0c;我强烈建议您学习并正确理解以下分析方法。 与过早的中间件&#xff08;Weblogic&#xff09;重…

java 可以重载等于号码_Java面试之Java基础4——重载与重写的区别

目录重载与重写的概念重载与重写的区别重载与重写的总结构造器是否能被重写override为什么函数不能根据返回类型来区分重载重载与重写的概念重载&#xff1a;同样一个方法可以根据输入参数列表的不同&#xff0c;做出不同的处理。普通方法和构造器方法都能够重载。方法重载&…

二维数组、多维数组

二维数组&#xff1a; 定义二维数组 int[,] myArray new int[几个一维数组,数组中的个数]; 数组可以具有多个维度。例如&#xff0c;下列声明创建一个四行两列的二维数组(可以理解为4个1维数组&#xff0c;数组中包含2个元素)&#xff1a; int[,] myArray new int[4,2]; int[…

一张大图片有多个小图片

这个页面也是我看到别人的写的&#xff0c;感觉不错&#xff0c;就自己留下了为了以后自己可以容易找到&#xff0c;也希望可以方便到别人。 写这个页面 需要注意的是&#xff1a; 1.写每一个小图片的位置时候&#xff0c;要用id,这样等级就高了&#xff0c;不然不起作用。 2.因…

Android Studio混淆

这一篇说一下Android Studio的代码混淆&#xff1a; 第一步&#xff1a;要想使混淆生效&#xff0c;要修改项目&#xff08;App&#xff09;下的build.gradle一处内容&#xff1a;minifyEnabled 的值 设置为true&#xff0c;当前项目就可以使用混淆了。 apply plugin: com.and…

Java 8:测试Lambda水

Java 8大约有一年的时间了&#xff0c;它具有我非常期待的语言功能&#xff1a; Lambda Expression 。 令人遗憾的是&#xff0c;另一个重要功能Java平台模块已延迟到Java9。但是&#xff0c;将lambda表达式&#xff08;或闭包&#xff09;添加到该语言中将使Java编程变得更好。…

基于阀值的工作流引擎设计

最近在做工作流处理流程部分的工作&#xff0c;顺便研究了一下工作流引擎的一些设计理念和原理。由于以前接触过人工智能神经网络的一些东西&#xff0c;发现工作流引擎和神经网络还是颇有一些相似之处&#xff0c;都是满足一定的条件下向下一个节点传递。在神经网络的神经元中…

Git之安装管理

1.Git安装部署 Git是分布式的版本控制系统&#xff0c;我们只要有了一个原始Git版本仓库&#xff0c;就可以让其他主机克隆走这个原始版本仓库&#xff0c;从而使得一个Git版本仓库可以被同时分布到不同的主机之上&#xff0c;并且每台主机的版本库都是一样的&#xff0c;没有主…

Java执行程序服务类型

ExecutorService功能是Java 5附带的。它扩展了Executor接口&#xff0c;并提供了线程池功能来执行异步简短任务。 使用Java 6提供的ExecutorService接口有五种异步执行任务的方法。 ExecutorService execService Executors.newCachedThreadPool&#xff08;&#xff09;; 这…

MySQL的主动优化和被动优化_MySQL“被动”性能优化汇总!

年少不知优化苦&#xff0c;遇坑方知优化难。 ——村口王大爷本文内容导图如下&#xff1a;我之前有很多文章都在讲性能优化的问题&#xff0c;比如下面这些&#xff1a;当然&#xff0c;本篇也是关于性能优化的&#xff0c;那性能优化就应该一把梭子吗&#xff1f;还是要符合一…

python2

一、管理库的安装 安装pip 提示报错&#xff1a;安装pip提示No module named setuptools Windows环境下Python默认是没有安装setuptools这个模块的&#xff0c;这也是一个第三方模块。下载地址为http://pypi.python.org/pypi/setuptools。下载后直接运行ez_setup.py 参考地址&…

【图】最短路径——Floyed算法和Dijkstra算法

最短路径问题(floyed.cpp dijkstra.cpp) 题目描述平面上有n个点(n<100)&#xff0c;每个点的坐标均在-10000&#xff5e;10000之间。其中的一些点之间有连线。若有连线&#xff0c;则表示可从一个点到达另一个点&#xff0c;即两点间有通路&#xff0c;通路的距离为两点间的…

Java并发– CyclicBarrier示例

Java中的CyclicBarrier是JDK 5中java.util.Concurrent包中引入的同步器&#xff0c;以及其他并发实用程序&#xff08;如Counting Semaphore &#xff0c; BlockingQueue &#xff0c; ConcurrentHashMap等&#xff09;。CyclicBarrier与CountDownLatch类似&#xff0c;我们在上…

JasperReports JSF插件用例–简单列表报告

这是JasperReports JSF插件系列的第一篇“用例文章” &#xff0c;我将专注于一个简单的需求&#xff0c;并且我将进一步深入。 起点是我们已经为图书商店完成的项目设置&#xff0c;我将向其中添加一个列表&#xff0c;其中包含在数据库中注册的其他图书&#xff0c;该列表也将…

ER图流程图

ER图&#xff1a;ER图分为实体、属性、关系三个核心部分。实体是长方形体现&#xff0c;而属性则是椭圆形&#xff0c;关系为菱形。 图书馆管理系统流程图&#xff08;图片源于网上&#xff09;&#xff1a;对于程序员来说&#xff0c;我们要知道&#xff1a;整个系统中&#x…

php源码仿三一重工,织梦仿三一重工业大学气企业网站php源码

★模板引荐★源码称呼&#xff1a;仿三一重工业大学气企业网站php源码仿三一重工业大学气企业网站php源码&#xff0c;尝试完备无错&#xff0c;兼容合流欣赏器。模板包括安置证明&#xff0c;并包括尝试数据。本模板鉴于DEDECms 5.7 GBK安排&#xff0c;须要 UTF-8版本的请本人…

php树莓派魔镜,用树莓派和显示器制作一面“魔镜”

所需要的材料一台显示器一块和显示器大小相同的双面镜一些2*4米的细木条树莓派机器必要组件(电源、HDMI线、usb无线网卡、键盘)木工工具(锯子、磨砂机、螺丝刀)螺丝、液态钉子选一个合适的显示器镜子的大小完全由显示器的类型和大小决定&#xff0c;所以我希望得到一个尽量大的…

【数字图像处理】[3]--直方图规范化

【数字图像处理】[3]--直方图规范化直方图规范化出现的原因是因为直方图均衡只能产生出固定的图像&#xff0c;不满足于需求&#xff0c;有时我们需要让直方图变成特定的直方图&#xff0c;于是有了直方图规范化原理&#xff1a;可能只看公式没什么感觉&#xff0c;我们来举一个…

JavaFX 2.0布局窗格– GridPane

毫无疑问&#xff0c; GridPane是JavaFX 2.0中功能最强大&#xff0c;最灵活的布局窗格。 它在由行和列组成的灵活网格中布置其子项&#xff0c;与Swing的GridBagLayout或HTML的表格模型非常相似。 这种方法使该窗格非常适合于任何形式的表单&#xff08;例如网站上的联系表单&…