简单的web services: html
如今咱们将开始了解什么是tornado,tornado能够作什么。咱们来经过分析tornado实现的一个简单web service 例子开始吧。 python
Hello Tornado 程序员
tornado 是一个能够处理http请求的框架,你的工做是做为一个程序员,编写一个handlers来响应一个标准的http请求。,下面是这个例子的全部代码: web
范例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命令测试这个应用: app
- $ 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函数库,可是在这个例子中你只须要导入四个函数库就能够运行了: curl
- 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,并使用默认值)
Code ViewCopyPrint
- 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.
curl命令显示的是两行命令,可是咱们输入的应该只是一行的命令,因此咱们使用双引字符(>>)来表示命令行的延续
这个字符串服务的例子大部分代码和上一个例子是相同的,让咱们将注意力集中到那些新增的不一样代码中来,首先让咱们来看看程序中传送给handlers的变量有什么不一样:
- app = tornado.web.Application(handlers=[
- (r"/reverse/(\w+)", ReverseHandler),
- (r"/wrap", WrapHandler)
- ])
在这个例子的代码中,咱们能够看到有两个RequestHandlers实例化的类对Handlers进行处理,第一个tornado请求的地址按照下面的正则表达式进行匹配:
这个正则表达式告诉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的值。
- # matched with (r”/widget/(\d+)”, WidgetHandler)
- class WidgetHandler(tornado.web.RequestHandler):
- def get(self, widget_id):
- widget = retrieve_from_db(widget_id)
- self.write(widget.serialize())
- def post(self, widget_id):
- widget = retrieve_from_db(widget_id)
- widget['foo'] = self.get_argument(‘foo’)
- save_to_db(widget)
截止目前咱们讨论的例子中只使用了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默认将会发送一个包含错误代码和错误信息的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.
下一步
如今你对tornado已经有了基本的理解,咱们但愿你能有迫切学习更多知识的动力。在后续的章节,咱们将向你展现更多的功能和技术,帮助你使用tornado去创建一个完整的web server和web应用。
原创翻译,首发地址:http://blog.xihuan.de/tech/web/tornado/
上一篇:翻译:introduce to tornado - introduce
下一篇:翻译:introduce to tornado - form and template