tornado

1.Tornado是使用Python开发的全栈式(full-stack)Web框架和异步网络库,最早由Friendfeed开发。通过使用非阻塞IO,Tornado可以处理数以万计的开放连接,是long polling、WebSockets和其他需要为用户维护长连接应用的理想选择。

Tornado 跟其他主流的Web服务器框架(主要是Python框架)不同是采用epoll非阻塞IO,响应快速,可处理数千并发连接,特别适用用于实时的Web服务。

Tornado 主要分成四个部分:

  • Web 框架(包括 RequestHandler,用于创建Web程序的基类,以及各种支持类)

  • 实现 HTTP 的客户端和服务器端 (HTTPServer 和 AsyncHTTPClient).

  • 一个异步网络库 (IOLoop 和 IOStream)

  • 一个协程库(tornado.gen) ,使得异步调用代码能够以更直接的方式书写,取代回调链接

2.下载与安装Tornado

我们可以在Tornado的官网上下载Tornado的压缩包(很小,只有大约300+k),然后执行下面的步骤进行离线安装:

当然也可以使用pip进行安装:

在Windows下执行离线安装时,使用Linux下离线安装的后两句(删除sudo),安装后执行下面的Hello World没有问题,但更多的功能可能会受限,没有进行尝试。

3.Hello World

下面使用《Introduction to Tornado》第一章中的例子作为Hello World,因为它相比于官网的例子多介绍了 1.命令行参数的使用;2.get参数。

加执行权限后,执行./hello.py --port=12345启动服务器。

在本地浏览器打开http://localhost:12345/可以看到:
Hello, tornado!

打开http://192.168.86.132:12345/?greeting=Bye可以看到:
Bye, tornado!

下面来逐句进行解释:

行4-7:引入tornado的部分模块。

行9-10:tornado.options模块可以从命令行中读取配置,如同shell里面的getopt一样。这里我们定义了一个设置选项,名为port,即端口。default表示默认值,help表示在帮助中显示的信息,type表示该设置参数的类型,如果类型匹配错误会报错。

行12-15:这是一个页面请求的Handler。目前只有一个get方法,该方法表示Http的Get请求。
RequestHandler类有一些有用的内建方法,其中get_argument可以用来像上面执行过程中的第二个网址一样添加参数,如果没有则显示为默认值(get_argument方法的第二个参数)。
而另一个常用的内建方法write,它的目的是将其中的字符串写在页面中。

行18:从命令行中取得配置参数。

行19:建立一个tornado应用。handlers是一个由一系列二元组组成的列表,其中每个二元组的第一个元素是一个正则表达式,表示网址路由,如果其中包含捕获分组,则将匹配的内容送往RequestHandler;第二个元素是所使用的RequestHandler类。

行20:使用这个tornado应用创建一个http服务器。

行21:设置http服务器的监听端口。

行22:启动服务器。

安装tornado

yum install python-setuptools
easy_install tornado

初识Tornado:一个简单例子


简单的web services:

现在我们将开始了解什么是tornado,tornado可以做什么。我们来通过分析tornado实现的一个简单web service 例子开始吧。

Hello Tornado

tornado 是一个可以处理http请求的框架,你的工作是作为一个程序员,编写一个handlers来响应一个标准的http请求。,下面是这个例子的所有代码:

范例1:hello.py

import tornado.httpserver   
import tornado.ioloop   
import tornado.options   
import tornado.web   
from tornado.options import define, options   
define(port, default=8000, help=run on the given port, type=int)

class IndexHandler(tornado.web.RequestHandler):   
    def get(self):   
        greeting = self.get_argument(greeting, Hello)   
        self.write(greeting + , friendly user!’)

if __name__ == __main__:   
    tornado.options.parse_command_line()   
    app = tornado.web.Application(handlers=[(r"/", IndexHandler)])   
    http_server = tornado.httpserver.HTTPServer(app)   
    http_server.listen(options.port)   
    tornado.ioloop.IOLoop.instance().start()

实际上我们大部分的工作是使用tornado的接口去定义一个类来扩展tornado 的RequestHandler类,在这个例子中,我们将会定义一个简单的应用来监听从端口获得的请求,并且返回一个响应值。

你可以通过命令行去试着运行和测试你自己的代码:

$ python hello.py –port=8000

现在你可以通过浏览器访问http://localhost:8000/,或者在另外一个独立的命令行窗口使用curl命令测试这个应用:

$ curl http://localhost:8000/   
Hello, friendly user!   
$ curl http://localhost:8000/?greeting=Salutations   
Salutations, friendly user!

让我们回到这个例子下,一步一步对它进行分析吧!

import tornado.httpserver   
import tornado.ioloop   
import tornado.options   
import tornado.web

在程序的最上面,我们导入各种tornado的函数库,这里还包括更多的tornado函数库,但是在这个例子中你只需要导入四个函数库就可以运行了:

from tornado.options import define, options   
define(port, default=8000, help=run on the given port, type=int)

tornado集成了一些有用的函数在tornado.options里面,在这里我们使用这个函数库来完成监听HTTP请求的应用,这些参数将会对所有对象生效,如果你是在命令行中输入–help,你将会看到所有的帮助信息及其定义。如果你没有输入一个值,那么default变量后面的参数将会作为默认值开始执行,假如你输入的是一个错误的类型,程序将会抛出一个错误,在这里允许使用一个整数型数据作为监听的端口,如果没有输入任何数据,程序将会使用默认端口8000。

class IndexHandler(tornado.web.RequestHandler):   
    def get(self):   
        greeting = self.get_argument(‘greeting’, ’Hello’)   
        self.write(greeting + ’, friendly user!’)

这是一个tornado处理请求的类,当出现请求时,tornado实例将会调用这个类和方法。在这个例子中,我们只定义了一个get方法,这意味着程序只能处理HTTP GET的请求,在后面我们将会学习到如何使用更多接口去响应HTTP不同的请求。

greeting = self.get_argument(‘greeting’, ’Hello’)

tornado的请求类拥有很多有用的方法,比如get_argument,这个方法可以让我们获得请求字符串中的变量(如果请求中不包含字符串,tornado将会使用第二种方法替代get_argument,并使用默认值)

self.write(greeting + ', friendly user!')

第二个方法是使用一个请求的方法,当请求中有字符串变量时,我们将会获取这个字符串,并且插入一个问候语响应这条请求。

if __name__ == "__main__":   
    tornado.options.parse_command_line()   
    app = tornado.web.Application(handlers=[(r"/", IndexHandler)])

tornado的应用将会从这里开始执行,首先我们通过tornado的options函数库去解析命令,当我们创建一个tornado应用类的实例的时候,所有导入的变量将会传送到类的 __init__ 方法中,这个方法将会告诉tornado需要调用哪一个handle ,我们将会在后面对此做详细的说明。

http_server = tornado.httpserver.HTTPServer(app)   
http_server.listen(options.port)   
tornado.ioloop.IOLoop.instance().start()

程序将从这里开始执行,创建一个实例,我们通过应用tornado的HTTPServer对象来监听指定的端口在命令行中获取的数据,然后我们创建一个tornado的IOLoop实例,最后这个程序将会开始接收HTTP请求。

操作的变量

让我们再回头看看helly.py这个例子的第一行:

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

这个handlers非常重要,我们将会在后面对它进行更详细的解释,它是一个元组的列表,我们使用一个正则表达式将它与RequestHandler进行匹配,你可以添加更多的列表来指定更多需要匹配的RequestHandler

使用正则表达式来指定URL

tornado使用正则表达式来匹配URL的http请求(RequestHandler的类在URL后面,不包括主机名和查询字符串的片段),它们应该包含起始行和结束行。当一个正则表达式匹配一个HTTP请求时,匹配的内容将会作为参数传递给RequestHandler的类。我们将会在下一个例子了解到它是如何工作的。

字符串服务

我们将通过一个稍微复杂一些的例子1-2去介绍更多关于tornado的设计理念.

例1-2 Handling input: string_service.py

import textwrap  
import tornado.httpserver   
import tornado.ioloop   
import tornado.options   
import tornado.web   
from tornado.options import define, options   
define(“port”, default=8000, help=”run on the given port”, type=int)   
class ReverseHandler(tornado.web.RequestHandler):   
    def get(self, input):   
        self.write(input[::-1])

class WrapHandler(tornado.web.RequestHandler):   
    def post(self):   
        text = self.get_argument(‘text’)   
        width = self.get_argument(‘width’, 40)   
        self.write(textwrap.fill(text, width))

if __name__ == __main__“:   
    tornado.options.parse_command_line()   
    app = tornado.web.Application(   
        handlers=[   
            (r"/reverse/(\w+)", ReverseHandler),   
            (r"/wrap", WrapHandler)   
        ]   
    )   
    http_server = tornado.httpserver.HTTPServer(app)   
    http_server.listen(options.port)   
    tornado.ioloop.IOLoop.instance().start()

和第一个例子一样,你可以像这样在命令行中运行它

$ python string_service.py –port=8000

这个程序是一个用于处理字符串的基础web框架,现在你可以对它做两件事情。

第一:通过GET向 /reverse/string请求返回一个特定的字符串,类似这样的URL结构

$ curl http://localhost:8000/reverse/stressed   
desserts   
$ curl http://localhost:8000/reverse/slipup   
pupils

第二:通过POST向/wrap提交请求,并将返回的字符串显示出来。这个请求包括一个无长度限制的字符串,在程序中,我们通过get_argument来接收这个字符串变量。你可以这么测试:

$ curl http://localhost:8000/wrap >>   
-d text=Lorem+ipsum+dolor+sit+amet,+consectetuer+adipiscing+elit.

结果 :

Lorem ipsum dolor sit amet, consectetuer   
adipiscing elit.

这个字符串服务的例子大部分代码和上一个例子是相同的,让我们将注意力集中到那些新增的不同代码中来,首先让我们来看看程序中传送给handlers的变量有什么不同:

app = tornado.web.Application(handlers=[   
    (r"/reverse/(\w+)", ReverseHandler),   
    (r"/wrap", WrapHandler)   
])

在这个例子的代码中,我们可以看到有两个RequestHandlers实例化的类对Handlers进行处理,第一个tornado请求的地址按照下面的正则表达式进行匹配:

/reverse/(\w+)

这个正则表达式告诉tornado,他将会匹配一个/reverse/后面跟着一个或多个数字、字母的字符串,括号的含义是告诉tornado,需要将括号中匹配的字符串作为RequestHandler的请求参数,我们可以查看ReverseHandler的定义去了解它是如何工作的:

class ReverseHandler(tornado.web.RequestHandler):   
    def get(self, input):   
        self.write(input[::-1])

你可以看到这个类中,get方法需要输入一个额外的参数,这个参数是在第一个正则表达式中,完全匹配括号内的表达式的一个字符串,(假如有多个括号分割的正则表达式,可以按照相同的顺序在get中添加接收的参数的变量)

现在,让我们来看看WrapHandler的定义:

class WrapHandler(tornado.web.RequestHandler):   
    def post(self):   
        text = self.get_argument(‘text’)   
        width = self.get_argument(‘width’, 40)   
        self.write(textwrap.fill(text, width))

WrapHandler的类会处理从请求中传过来的字符串。我们可以看到这个类只定义了一个post的方法,这意味着它只能接收HTTP post的方法。我们之前是用过这个RequestHandler对象来抓取从请求中传过来的字符串作为变量。现在我们可以使用同样的方法去抓取POST请求传过来的变量(tornado可以解析POST传过来的URL字符串或参数),一旦我们抓取到了字符串及其长度的参数,就可以使用python内置的textwrap函数库库去转换字符串,并且通过HTTP返回生成的字符串作为响应数据。

更多RequestHandlers

到目前为止,我们基于RequestHandler开发这些对象:如何通过HTTP获取参数(使用get_argument 获取GET和POST传递过来的参数)和如何编写HTTP相应信息(使用write方法)。在我们开始后面的章节学习之前,再给你介绍一些应用RequestHandler需要注意的地方,以及tornado如何去使用它。

http方法:

截止目前讨论的都是关于RequestHandler定义单个HTTP方法的问题,其实在一个类中,可以定义或使用多个 handler,绑定多个功能到一个类中是一种很好的管理方式,你可能会编写一个处理程序去获取参数,并且通过POST和GET对象改变数据库中一个特定ID的值,例如:用一个GET方法中将抓取请求的ID和参数,并且使用POST方法修改数据库中对应ID的值。

截止目前我们讨论的例子中只使用了GET 和 POST的方法,实际上tornado还支持更多的HTTP方法(GET,POST,PUT,DELETE,HEAD,OPTIONS),在你编写的RequestHandler类中可以通过定义不同的方法去使用他们。在下面的虚拟案例中,我们将会使用HEAD方法去判断请求中的frob是否存在于数据库中,当存在时我们通过GET方法将frob对应的数据库信息返回给请求的客户端:

# matched with (r"/frob/(\d+)", FrobHandler)   
class FrobHandler(tornado.web.RequestHandler):   
    def head(self, frob_id):   
        frob = retrieve_from_db(frob_id)   
        if frob is not None:   
            self.set_status(200)   
        else:   
            self.set_status(404)   
    def get(self, frob_id):   
        frob = retrieve_from_db(frob_id)   
        self.write(frob.serialize())

HTTP状态码:

在上一个展示的例子中,你可以在你的RequestHandler使用set_status()设置HTTP状态码到客户端的相应信息中,下面是一些比较重要的状态码。tornado也可以根据你的相应自动去返回对应的状态码,在这里我们只列出比较常用的几个状态码:

  • 404 Not Found

如果HTTP请求的路径不存在,tornado将会通过RequestHandler类自动将404(Not Found)返回给客户端

  • 400 Bad Request

如果使用get_argument没有获取到默认的参数哦,或者没有找到定义的参数名,tornado将会自动将400(Bad Request)返回给客户端。

  • 405 Method Not Allowed

如果通过HTTP传进来的请求没有找到RequestHandler类中对应的方法(例如使用POST请求,但是handler方法对应的类却是GET方法)tornado将会返回一个405(Method Not Allowed)给客户端。

  • 500 Internal Server Error

当遇到任何应用服务异常退出的错误时,tornado将会返回500( Internal Server Error)给客户端,代码中任何意外退出都可能导致tornado返回一个500错误代码。

  • 200 OK

如果请求成功完成了,并且没有设置其它相应代码,tornado默认将会自动返回一个200(OK)的响应给客户端。

如果请求成功完成了,并且没有设置其它相应代码,tornado默认将会自动返回一个200(OK)的响应给客户端。

当出现一个错误出现时,tornado默认将会发送一个包含错误代码和错误信息的html页面给客户端,如果你想要替换默认响应的错误信息成自定义的页面,你可以在你的RequestHandler中重写write_error方法,例子1-3将会向你展示我们修改的hello.py,让你了解如何将初始化的错误信息重新改写。

import tornado.httpserver   
import tornado.ioloop   
import tornado.options   
import tornado.web   
from tornado.options import define, options

define("port", default=8000, help=run on the given port, type=int)

class IndexHandler(tornado.web.RequestHandler):   
    def get(self):   
        greeting = self.get_argument(greeting, Hello)   
        self.write(greeting + , friendly user!’)   
    def write_error(self, status_code, **kwargs):   
        self.write(Gosh darnit, user! You caused a %d error. % status_code)

if __name__ == __main__:   
    tornado.options.parse_command_line()   
    app = tornado.web.Application(handlers=[(r"/", IndexHandler)])   
    http_server = tornado.httpserver.HTTPServer(app)   
    http_server.listen(options.port)   
    tornado.ioloop.IOLoop.instance().start()

在当我们使用POST向handler发送请求时,将会出现下面的响应,因为我们已经把tornado默认的错误响应重写了:

$ curl -d foo=bar http://localhost:8000/   
Gosh darnit, user! You caused a 405 error.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值