Tornado是使用Python编写的一个强大的、可扩展的Web服务器。它在处理严峻的网络流量时表现得足够强健,但却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中。

tornado技术文档:Tornado文档中文翻译版

ubuntu下安装tornado: pip install tarnado  (其他安装方式自行百度)

Tornado 主要服务分为  服务器模块(httpserver)    IO接口模块(ioloop)    web模块(web)

TORNADO 项目的简单创建

初步使用这三大模块来建立一个简易的 web 服务

 #导入相关服务模块

 import tornado.httpserver

 import tornado.ioloop

 import tornado.web

 class IndexHandler(tornado.web.RequestHandler):
def get(self):
greeting = self.get_argument('greeting', 'Hello')
self.write(greeting + ', friendly user!') if __name__ == "__main__": app = tornado.web.Application(
handlers=[(r"/", IndexHandler)]
)
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(8000)
tornado.ioloop.IOLoop.current().start()

以上就是一个简单的web服务,通过访问该 ip 的8000端口 就能访问到设置的相关信息或界面!

我们来认识一下上面的相关代码:

类 IndexHandler 是一个句柄:描述控制器操作过程的一个动作

在app中设置路由及其他一些操作,参数handlers非常重要,它应该是一个元组组成的列表,其中每个元组的第一个元素是一个用于匹配的正则表达式,第二个元素是一个RequestHanlder类(即句柄)。你可以按你的需要指定任意多个。

通过 tornado.httpserver.HTTPServer 绑定 Application 对象

通过 tornado.httpserver.HTTPServer().listen() 设置监听端口

通过 tornado.ioloop.IOLoop.current().start() 开始循环监听端口

TORNADO 框架的初步应用

下面开始真正探讨 Tornado 的一些模块与功能:

全局变量的定义:

 import  tornado.options

 tornado.options.define(“port” , default = 8888,type = int, help = “程序启动端口”)

 tornado.options.define(“msg”,default = “这是一条测试信息”)

以上就是全局变量的定义方法,我们定义了一个端口与一个“msg”测试信息。

使用全局变量:我们已经定义好了一个端口变量,现在我们来使用它,例如;

 port = tornado.options.options.port

 http_server.listen(port)

接受命令行参数:

 tornado.options.parse_command_line()

加载配置文件到程序中:

如:创建一个配置文件,文件名:config    文件内容:port = 8000

加载文件: tornado.options.parse_config_file(“./config”)

配置文件中的变量一定确保已经被 define 定义过!

指定网页模板目录和指定静态文件目录:

 import os

 BASE_DIR = os.path.dirname(__file__)

 template_path = os.path.join(BASE_DIR,“templates”)

 static_path = os.path.join(BASE_DIR,“static”)

定义路径的语句app中,模板与静态文件为同级目录下的 templates 与 static 文件夹

 app = tornado.web.Application(
handlers=[(r"/", IndexHandler)], debug = True #开启开发调试模式template_path = os.path.join(BASE_DIR,“templates”)
static_path = os.path.join(BASE_DIR,“static”)
)
使用static_url生成静态URL:
 <link rel="stylesheet" href="{{ static_url("style.css") }}">
#生成了类似下面的代码
<link rel="stylesheet" href="/static/style.css?v=ab12">

数据的传输:

get方式接收 –>

单个数据:get_query_argument()     多个数据:get_query_arguments()

post方式接收 –>

单个数据:get_body_argument()     多个数据:get_body_arguments()

未指定方式接收 –>

单个数据:get_argument()     多个数据:get_arguments()

HTTP状态码:

404 Not Found

Tornado会在HTTP请求的路径无法匹配任何RequestHandler类相对应的模式时返回404(Not Found)响应码。

400 Bad Request

如果你调用了一个没有默认值的get_argument函数,并且没有发现给定名称的参数,Tornado将自动返回一个400(Bad Request)响应码。

405 Method Not Allowed

如果传入的请求使用了RequestHandler中没有定义的HTTP方法(比如,一个POST请求,但是处理函数中只有定义了get方法),Tornado将返回一个405(Methos Not Allowed)响应码。

500 Internal Server Error

当程序遇到任何不能让其退出的错误时,Tornado将返回500(Internal Server Error)响应码。你代码中任何没有捕获的异常也会导致500响应码。

200 OK

如果响应成功,并且没有其他返回码被设置,Tornado将默认返回一个200(OK)响应码。

使用自己的方法代替默认的错误响应,你可以重写write_error方法在你的RequestHandler类中。

 def write_error(self, status_code, **kwargs):
self.write("Gosh darnit, user! You caused a %d error." % status_code)

cookies设置:

Cookie 是由 Web 服务器保存在用户浏览器(客户端)上的小文本文件,它可以包含有关用户的信息。无论何时用户链接到服务器,Web 站点都可以访问 Cookie 信息 。

会话跟踪是一种灵活、轻便的机制,它使Web上的状态编程变为可能。
HTTP是一种无状态协议,每当用户发出请求时,服务器就会做出响应,客户端与服务器之间的联系是离散的、非连续的。
当用户在同一网站的多个页面之间转换时,根本无法确定是否是同一个客户,会话跟踪技术就可以解决这个问题。
当一个客户在多个页面间切换时,服务器会保存该用户的信息。
有四种方法可以实现会话跟踪技术:URL重写、隐藏表单域、Cookie、Session。

存入数据:

 self.set_cookie(“msg”:”这是一条测试信息!”)                #一般安全cookie

 ————————————————————————————————————————

 self.set_secure_cookie(“msg”:”这是一条安全cookie测试信息!”)            #安全cookie

 #!!!设置安全cookie前必须具有混淆码    设置方式如下

 # 1.生成一个混淆码

 # import uuid,base64

 # code =  base64.b64encode(uuid.uuid4().bytes+uuid.uuid4().bytes)

 # 2.将混淆码加入cookie设置(在app里添加以下代码)

 # cookie_secret = “%s”%code

 ————————————————————————————————————————

 #可以向set_cookie和set_secure_cookie方法传递关键字参数。比如,一个安全的HTTP-only cookie(上面的安全cookie其实是签名cookie)可以调用self.set_cookie('foo', 'bar', httponly=True, secure=True)发送。

设置过期时间的 cookie 为永久 cookie , 没有设置的为临时 cookie,如:

self.set_cookie(“msg”:”这是一条测试信息!”,expires_day = 1)

读取数据:

 self.get_cookie(“msg”)

 self.get_secure_cookie()

cookie认证装饰器:

  1. 引入装饰器    -> –>      from tornado.web import authenticated
  2. 在需要装饰的方法前加     -> –>     @authenticated
  3. 在 app 中添加认证失败的跳转地址    -> –>       login_url = “/login”
  4. 重写装饰器中获取数据函数
     def  get_current_user(self):
    
             status = self.get_secure_cookies(“login_user”)
    
             if status:
    
                     return True
    
              return  False

跨域请求伪造防范:

跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制。

任何Web应用所面临的一个主要安全漏洞是跨站请求伪造,通常被简写为CSRF或XSRF,发音为"sea surf"。这个漏洞利用了浏览器的一个允许恶意攻击者在受害者网站注入脚本使未授权请求代表一个已登录用户的安全漏洞。

app 中添加 xsrf——cookies = True

html页面提交表单中加入 {% module xsrf_form_html( ) %}

XSRF令牌和AJAX请求:

AJAX请求也需要一个_xsrf参数,但不是必须显式地在渲染页面时包含一个_xsrf值,而是通过脚本在客户端查询浏览器获得cookie值。下面的两个函数透明地添加令牌值给AJAX POST请求。第一个函数通过名字获取cookie,而第二个函数是一个添加_xsrf参数到传递给postJSON函数数据对象的便捷函数。

 function getCookie(name) {
var c = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return c ? c[1] : undefined;
} jQuery.postJSON = function(url, data, callback) {
data._xsrf = getCookie("_xsrf");
jQuery.ajax({
url: url,
data: jQuery.param(data),
dataType: "json",
type: "POST",
success: callback
});
}

同步与异步:

大部分Web应用(包括我们之前的例子)都是阻塞性质的,也就是说当一个请求被处理时,这个进程就会被挂起直至请求完成。在大多数情况下,Tornado处理的Web请求完成得足够快使得这个问题并不需要被关注。然而,对于那些需要一些时间来完成的操作(像大数据库的请求或外部API),这意味着应用程序被有效的锁定直至处理结束,Tornado给了我们更好的方法来处理这种情况。应用程序在等待第一个处理完成的过程中,让I/O循环打开以便服务于其他客户端,直到处理完成时启动一个请求并给予反馈,而不再是等待请求完成的过程中挂起进程。

这里用一个简单的例子来实现同步与异步:

Eg:向淘宝发起搜索请求:https://suggest.taobao.com/sug?code=utf-8&q=(关键字)

先写一个同步的简例

 import  tornado.web

 import tornado.httpserver

 import tornado.httpclient

 import tornado.ioloop

 import urllib,json

 class IndexHandler(tornado.web.RequestHandler):

         def    get(self):

                 query = “iphonex”

                 client = tornado.httpclient.HTTPClient()

                 response = client.fetch(“https://suggest.taobao.com/sug?code=utf-8&”+urllib.parse.urlencode({“q”:query}))

         def deal_response(self,response):

                 content = response.body

                 self.write(response.body)

 if __name__  ==  “__main__”:

         app  =  tornado.web.Application(handlers  =  [(r”/”,IndexHandler)])

         app.listen(8000)

         tornado.ioloop.IOLoop.current().start()

再用异步的方式写一下:

 import  tornado.web

 import tornado.httpserver

 import tornado.httpclient

 import tornado.ioloop

 import urllib,json

 from tornado.httpclient  import AsyncHTTPClient

 class IndexHandler(tornado.web.RequestHandler):

         #异步请求装饰器,如果不添加,get函数会自动生成一个return,程序会报错

        @tornado.web.asynchronous

         def    get(self):

                 query = “iphonex”

                 client = tornado.httpclient.HTTPClient()

                 response = client.fetch(“https://suggest.taobao.com/sug?code=utf-8&”+urllib.parse.urlencode({“q”:query}),callback = self.deal_response)

                 self.write(response.body)

                 self.finish()         #回调函数结束时需要

 if __name__  ==  “__main__”:

         app  =  tornado.web.Application(handlers  =  [(r”/”,IndexHandler)])

         app.listen(8000)

         tornado.ioloop.IOLoop.current().start()

在运行程序过程中,从浏览器上感觉不出同步异步有什么不同,可以用 siege 压力测试一下:

(siege 安装方式:sudo apt-get install siege)

        

上图左边是同步测试,右边是异步测试(连接量10,时间10s)。可以看出相同环境下,异步的连接处理数是同步的六倍,异步平均每秒18.32,同步平均每秒只有3.58

模板语法

填充表达式:

 >>> from tornado.template import Template
>>> print Template("{{ 1+1 }}").generate()
2
>>> print Template("{{ 'scrambled eggs'[-4:] }}").generate()
eggs
>>> print Template("{{ ', '.join([str(x*x) for x in range(10)]) }}").generate()
0, 1, 4, 9, 16, 25, 36, 49, 64, 81

控制流语句:

在Tornado模板中使用Python条件和循环语句。控制语句以{%和%}包围

{% if page is None %}    或      {% if len(entries) == 3 %}

控制语句的大部分就像对应的Python语句一样工作,支持ifforwhiletry。在这些情况下,语句块以{%开始,并以%}结束。

 <h1>{{ header }}</h1>
<ul>
{% for book in books %}
<li>{{ book }}</li>
{% end %}
</ul>

模板函数:

escape(s)  
替换字符串s中的&、<、>为他们对应的HTML字符。
url_escape(s)

使用urllib.quote_plus替换字符串s中的字符为URL编码形式。

json_encode(val)

将val编码成JSON格式。(在系统底层,这是一个对json库的dumps函数的调用。查阅相关的文档以获得更多关于该函数接收和返回参数的信息。)

squeeze(s)

过滤字符串s,把连续的多个空白字符替换成一个空格。

模板扩展

块和替换:

为了扩展一个已经存在的模板,你只需要在新的模板文件的顶部放上一句{% extends "filename.html" %}

比如在一个新模板中扩展一个父模板(main.html):

{% extends "main.html" %}
块基础:
为了使用一个能够根据不同页覆写的动态header块,在父模板main.html中添加如下代码:
 <header>
{% block header %}{% end %}
</header>

然后,为了在子模板index.html中覆写{% block header %}{% end %}部分,你可以使用块的名字引用,并把任何你想要的内容放到其中。

 {% block header %}{% end %}

 {% block header %}
<h1>Hello world!</h1>
{% end %}

任何继承这个模板的文件都可以包含它自己的{% block header %}{% end %},然后把一些不同的东西加进去。

可以为每个页面使用多个块,此时像header和footer这样的动态元素将会被包含在同一个流程中。

父模板main.html:

 <html>
<body>
<header>
{% block header %}{% end %}
</header>
<content>
{% block body %}{% end %}
</content>
<footer>
{% block footer %}{% end %}
</footer>
</body>
</html>

当我们扩展父模板main.html时,可以在子模板index.html中引用这些块。

 {% extends "main.html" %}

 {% block header %}
<h1>{{ header_text }}</h1>
{% end %} {% block body %}
<p>Hello from the child template!</p>
{% end %} {% block footer %}
<p>{{ footer_text }}</p>
{% end %}
自动转义:

Tornado默认会自动转义模板中的内容,把标签转换为相应的HTML实体。

当不需要转义时,你可以禁用自动转义,一种方法是在Application构造函数中传递autoescape=None,另一种方法是在每页的基础上修改自动转义行为,如下所示:

 {% autoescape None %}
{{ mailLink }}

这些autoescape块不需要结束标签,并且可以设置xhtml_escape来开启自动转义(默认行为),或None来关闭。

然而,在理想的情况下,你希望保持自动转义开启以便继续防护你的网站。因此,你可以使用{% raw %}指令来输出不转义的内容。

{% raw mailLink %}

需要特别注意的是,当你使用诸如Tornado的linkify()xsrf_form_html()函数时,自动转义的设置被改变了。所以如果你希望在前面代码的footer中使用linkify()来包含链接,你可以使用一个{% raw %}块:

 {% block footer %}
<p>
For more information about our selection, hours or events, please email us at
<a href="mailto:[email protected]">[email protected]</a>.
</p> <p class="small">
Follow us on Facebook at
{% raw linkify("https://fb.me/burtsbooks", extra_params='ref=website') %}.
</p>
{% end %}

这样,你可以既利用linkify()简记的好处,又可以保持在其他地方自动转义的好处。

嵌入JavaScript和CSS:

Tornado允许你使用embedded_cssembedded_javascript方法嵌入其他的CSS和JavaScript文件。

例如,你想在调用模块时给DOM添加一行文字,你可以通过从模块中嵌入JavaScript来做到:

 class BookModule(tornado.web.UIModule):
def render(self, book):
return self.render_string(
"modules/book.html",
book=book,
) def embedded_javascript(self):
return "document.write(\"hi!\")"

当调用模块时,document.write(\"hi!\")将被<script>包围,并被插入到<body>的闭标签中:

 <script type="text/javascript">
//<![CDATA[
document.write("hi!")
//]]>
</script>

你也可以把只在这些模块被调用时加载的额外的CSS规则放进来:

 def embedded_css(self):
return ".book {background-color:#F5F5F5}"

在这种情况下,.book {background-color:#555}这条CSS规则被包裹在<style>中,并被直接添加到<head>的闭标签之前。

 <style type="text/css">
.book {background-color:#F5F5F5}
</style>

甚至可以简单地使用html_body()来在闭合的</body>标签前添加完整的HTML标记:

 def html_body(self):
return "<script>document.write(\"Hello!\")</script>"

为了更严谨的包含(以及更整洁的代码!),添加样式表和脚本文件会显得更好。他们的工作方式基本相同,所以你可以使用javascript_files()css_files()来包含完整的文件,不论是本地的还是外部的。

 #添加个本地的css文件
def css_files(self):
return "/static/css/newreleases.css" #添加一个外部的JavaScript文件:
def javascript_files(self):
return "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js"

因为模块的内嵌JavaScript和内嵌HTML函数的目标都是紧邻</body>标签,html_body()javascript_files()embedded_javascript()都会将内容渲染后插到页面底部,那么它们出现的顺序正好是你指定它们的顺序的倒序。

 class SampleModule(tornado.web.UIModule):
def render(self, sample):
return self.render_string(
"modules/sample.html",
sample=sample
) def html_body(self):
return "<div class=\"addition\"><p>html_body()</p></div>" def embedded_javascript(self):
return "document.write(\"<p>embedded_javascript()</p>\")" def embedded_css(self):
return ".addition {color: #A1CAF1}" def css_files(self):
return "/static/css/sample.css" def javascript_files(self):
return "/static/js/sample.js"

html_body()最先被编写,它紧挨着出现在</body>标签的上面。embedded_javascript()接着被渲染,最后是javascript_files()

不能包括一个需要其他地方东西的方法(比如依赖其他文件的JavaScript函数),因为此时他们可能会按照和你期望不同的顺序进行渲染。

WebSockets:

WebSockets是HTML5规范中新提出的客户-服务器通讯协议。WebSocket协议提供了在客户端和服务器间持久连接的双向通信。协议本身使用新的ws://URL格式,但它是在标准HTTP上实现的。通过使用HTTP和HTTPS端口,它避免了从Web代理后的网络连接站点时引入的各种问题。HTML5规范不只描述了协议本身,还描述了使用WebSockets编写客户端代码所需要的浏览器API。

Tornado的WebSocket模块:

Tornado在websocket模块中提供了一个WebSocketHandler类。这个类提供了和已连接的客户端通信的WebSocket事件和方法的钩子。当一个新的WebSocket连接打开时,open方法被调用,而on_messageon_close方法分别在连接接收到新的消息和客户端关闭时被调用。

 class IndexHandler(tornado.websocket.WebSocketHandler):
def open(self):
self.write_message('connected!') def on_message(self, message):
self.write_message(message)

使用PyMongo进行MongoDB基础操作

Tornado项目简单创建的更多相关文章

  1. github上创建java项目简单操作

    github上创建java项目简单操作 参考L: github上创建java项目简单操作 - CSDN博客http://blog.csdn.net/qq_29392425/article/detail ...

  2. 简单创建一个SpringCloud2021.0.3项目(四)

    目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 上三篇教程 3. 日志处理 1. 创建日志公共模块 2. Eureka引入日志模块 4. 到此的功能代码 5. 注册中心换成naco ...

  3. 简单创建一个SpringCloud2021.0.3项目(三)

    目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 上俩篇教程 3. Gateway集成sentinel,网关层做熔断降级 1. 超时熔断降级 2. 异常熔断 3. 集成sentine ...

  4. 简单创建一个SpringCloud2021.0.3项目(二)

    目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 上一篇教程 3. 创建公共模块Common 4. 网关Gateway 1. 创建Security 2. Security登陆配置 3 ...

  5. 简单创建一个SpringCloud2021.0.3项目(一)

    目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 新建父模块和注册中心 1. 新建父模块 2. 新建注册中心Eureka 3. 新建配置中心Config 4. 新建两个业务服务 1. ...

  6. Web项目中创建简单的错误处理页面

    当应用程序出现错误的时候,如果没有做错误页面处理的话,会直接输出一些敏感的信息出来,有时候甚至会直接将项目所在的物理路径给显示出来,严重缺乏安全性,并且错误种类繁多,页面风格不一,导致用户体验不好,本 ...

  7. .net core 简单项目的创建

    1.linux 安装net coref https://www.microsoft.com/net/learn/get-started/linuxubuntu 2.创建目录 2.创建控制台项目 第一次 ...

  8. Centos7部署tornado项目

    今天帮一个学生解决tornado的部署问题,在此记录了这其中的过程,其中的tornado项目更换为demo示例. 开发环境: 本地开发环境:Win10 + Python3.5.4 + PyCharm ...

  9. maven系列之二maven项目的创建和maven项目的结构

    maven系列之一简单介绍了maven的基本信息,安装和配置,大家对maven有一个大概的了解,但是在maven项目开发中远远不够,为了进一步了解maven,现在我们介绍maven项目的创建和mave ...

随机推荐

  1. Myeclipse的一些快捷键整理(转)

    1. [ALT+/]    此快捷键为用户编辑的好帮手,能为用户提供内容的辅助,不要为记不全方法和属性名称犯愁,当记不全类.方法和属性的名字时,多体验一下[ALT+/]快捷键带来的好处吧.    2. ...

  2. hfs 文件存储

    hfs 服务器上面的和本地拖上去的文件是同一个文件.对本地文件拖上去之后再修改,服务器文件也会修改.所以服务器要有一个自己的文件存放.

  3. java项目中的异常处理总结

    异常指的是运行期出现的错误,也就是当程序开始执行以后执行期出现的错误.出现错误时观察错误的名字和行号最为重要. 比如你读取的文件不存在,数组越界,进行除法时,除数为0等都会导致异常. 我找一个比较形象 ...

  4. servlet中的“/”代表当前项目,html中的“/”代表当前服务器

    servlet中重定向或请求转发的路径如果用“/”开头,代表当前项目下的路径,浏览器转发这条路径时会自动加上当前项目的路径前缀,如果这个路径不是以“/”开头,那么代表这个路径和当前所在servlet的 ...

  5. php对字符串的操作3之 字符类型转换详解

    所有的数据输出到屏幕上,实际上被隐式的转换成了字符型,首先了解下各种数据类型的字符串表示 <?php echo 300,'<hr>'; echo true,'<hr>'; ...

  6. 计算几何-多边形内核判定-HPI-poj3335

    This article is made by Jason-Cow.Welcome to reprint.But please post the article's address. 先解决一个问题, ...

  7. 「题解」「JZOJ-4238」纪念碑

    题目 在 \(N\times M\) 的网格中,有 \(P\) 个矩形建筑,求一个最大边长的正方形,使得网格中能找到一个放置正方形的地方,不会与建筑重合. 保证 \(N,M\le 10^6,P\le ...

  8. Sql Server跨服务器操作数据

    var serversSql = "select count(*) count from sys.servers WHERE name='ITSV'"; var result = ...

  9. VMware 搭建linux虚拟机环境

    1.任务管理器-服务 确认VMware服务是否启动 2.VMware生成网关地址 编辑--虚拟网络编辑器 VMnet8 NAT设置子网IP,子网掩码,网关 3.windows网络--更改适配器设置-- ...

  10. Android学习14

    Fragment Fragment是依赖于Activity的,不能独立存在的. 一个Activity里可以有多个Fragment. 一个Fragment可以被多个Activity重用. Fragmen ...