tornado之HelloWorld

tornado是python的一个轻量级的web框架,主要特点是非阻塞式的,处理速度快,而且是轻量级的,使用方便。反之Django则是一个重量级的大而全的框架,功能较多,生态较全。


1 HelloWorld

直接看最简单的demo:

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

if __name__ == "__main__":
	application = tornado.web.Application([(r"/", MainHandler)])
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

启动后(注意,文件名不要用tornado命名),在地址栏输入localhost:8888/test即可看到输出:
在这里插入图片描述
分析一下这个简单的demo:
首先,生成一个Apptioncation实例,在构造函数中传入一个列表类型的参数(由url路径和处理类组成的元组)。
然后,调用Application的listen方法监听服务器端口,事实上该方法会先创建一个HTTPServer实例,然后在HTTPServer实例上进行监听,方法描述如下:

def listen(self, port, address="", **kwargs):
    """Starts an HTTP server for this application on the given port.

    This is a convenience alias for creating an `.HTTPServer`
    object and calling its listen method.  Keyword arguments not
    supported by `HTTPServer.listen <.TCPServer.listen>` are passed to the
    `.HTTPServer` constructor.  For advanced uses
    (e.g. multi-process mode), do not use this method; create an
    `.HTTPServer` and call its
    `.TCPServer.bind`/`.TCPServer.start` methods directly.

    Note that after calling this method you still need to call
    ``IOLoop.current().start()`` to start the server.

    Returns the `.HTTPServer` object.

    .. versionchanged:: 4.3
       Now returns the `.HTTPServer` object.
    """
    # import is here rather than top level because HTTPServer
    # is not importable on appengine
    from tornado.httpserver import HTTPServer
    server = HTTPServer(self, **kwargs)
    server.listen(port, address)
    return server

最后,执行IOLoop类的实例方法 start(),即可启动服务器。

注意:这种启动方式实际上是单进程模式,只适合学习使用,不适合正式生产环境。多进程模式将在下一篇blog中介绍-《tornado多进程》。

2 HelloWorld扩展

# coding: utf-8
import sys

reload(sys)
sys.setdefaultencoding('utf-8')

import tornado.ioloop
import tornado.web
import logging

from tornado.options import define, options

"""定义全局变量,这里定义了一个端口"""
define("port", default=8888, help="run on the given port", type=int)


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("hello world")


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


if __name__ == "__main__":
    logging.basicConfig(stream=sys.stdout, level=logging.INFO,
                        format='%(asctime)s %(levelno)s %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S',
                        )
    logging.info("start server ...")
    app = tornado.web.Application(handlers=[(r"/", IndexHandler), (r"/test", MainHandler)])
    app.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

这里添加了两个路由映射,直接输入服务器地址加端口ip,则映射到MainHandler,输出“hello world”。如果继续加一层子路径/test,则输出“Hello,friendly user!”。

如果要使用中文,则必须在文件头加上:

 # coding: utf-8
 import sys
 reload(sys)
 sys.setdefaultencoding('utf-8')

重载sys模块并设置编码方式为utf-8。

如果要打印日志,则需要在主函数里面加上:

logging.basicConfig(stream=sys.stdout, level=logging.INFO,
                        format='%(asctime)s %(levelno)s %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S',
                        )

表示在控制台输出日志,格式为:年月日时分秒 日志级别 日志内容。

2.1 参数处理

get请求

上面的例子中get请求都没有参数,如果get请求有参数呢?

定义处理类如下:

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

该处理类能接收get请求,并反序输出请求参数。
路由映射如下:

handlers=[(r"/reverse/(\w+)", ReverseHandler), xxx]

\w+匹配1个或多个字母、数字或下划线。括号的含义是让Tornado保存匹配括号里面表达式的字符串,并将其作为请求方法的一个参数传递给RequestHandler类。

启动服务器,通过地址栏发出get请求:http://localhost:8888/reverse/hello, 会将hello作为参数,反转输出"olleh"。
除了在url中通过正则表达式来匹配参数外,还可以通过在url中直接带上get参数,然后通过get_argument函数获取。

post请求

对于post请求,通过post方法进行处理。
引入textwrap,并定义handler类如下:

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

该处理类能接收post请求,并获取两个参数,分别是text和width,text未指定值,需要从命令行读取。最终截取text参数的前40个字符输出。
路由映射如下:

handlers=[(r"/wrap", WrapHandler), xxx]

post请求可以通过命令行curl xxx -d 指令发出:

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

输出结果如下(Tornado可以解析URLencoded和multipart结构的POST请求参数):

Lorem ipsum dolor sit amet, consectetuer

3 HTTP方法与状态码

下面将对RequestHandler进行更详细的介绍。

HTTP方法

通过上文可知,对于tornado.web.RequestHandler对象,从HTTP请求中获取信息的方式是:使用get_argument来获得get或post请求的参数;写HTTP响应的方式是:使用write方法。

事实上,Tornado支持任何合法的HTTP请求(GET、POST、PUT、DELETE、HEAD、OPTIONS),只要在RequestHandler类中使用同名的方法即可。熟悉http协议的都知道,http请求报文中包含请求方法的名称,因此很容易判断出http请求交由哪一个方法进行处理。

HTTP状态码

Http响应报文中则需要返回状态码,而状态码可以直接通过RequestHandler类的set_status()方法显式地设置。当然,正常情况下,tornado会自动设置HTTP状态码,如200表示成功,400表示错误的请求,405表示不被允许的请求等。

如果你想使用自己的方法代替默认的错误响应,可以通过重写write_error来实现。demo如下:

# coding: utf-8
import sys

reload(sys)
sys.setdefaultencoding('utf-8')

import tornado.ioloop
import tornado.web
import logging

from tornado.options import define, options

"""定义全局变量,这里定义了一个端口"""
define("port", default=8888, help="run on the given port", type=int)


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("hello world")


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__":
    logging.basicConfig(stream=sys.stdout, level=logging.INFO,
                        format='%(asctime)s %(levelno)s %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S',
                        )
    logging.info("start server")
    tornado.options.parse_command_line()
    app = tornado.web.Application(handlers=[(r"/", IndexHandler),
                                            (r"/test", MainHandler)])
    app.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

当尝试发起一个post请求时:$ curl -d foo=bar http://localhost:8888/ 会输出:Gosh darnit, user! You caused a 405 error.
如果不复写write_error方法,则默认输出:405: Method Not Allowed。

4 参考资料

[1]http://demo.pythoner.com/itt2zh/ch1.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值