• 【模块】:Tornado


    Tornado框架

    简介:

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

      我们现在所知道的Tornado是基于Bret Taylor和其他人员为FriendFeed所开发的网络服务框架,当FriendFeed被Facebook收购后得以开源。不同于那些最多只能达到10,000个并发连接的传统网络服务器,Tornado在设计之初就考虑到了性能因素,旨在解决C10K问题,这样的设计使得其成为一个拥有非常高性能的框架。此外,它还拥有处理安全性、用户验证、社交网络以及与外部服务(如数据库和网站API)进行异步交互的工具。

      自从2009年9月10日发布以来,TornadoTornado已经获得了很多社区的支持,并且在一系列不同的场合得到应用。除FriendFeed和Facebook外,还有很多公司在生产上转向Tornado,包括Quora、Turntable.fm、Bit.ly、Hipmunk以及MyYearbook等。

      总之,如果你在寻找你那庞大的CMS或一体化开发框架的替代品,Tornado可能并不是一个好的选择。Tornado并不需要你拥有庞大的模型建立特殊的方式,或以某种确定的形式处理表单,或其他类似的事情。它所做的是让你能够快速简单地编写高速的Web应用。如果你想编写一个可扩展的社交应用、实时分析引擎,或RESTful API,那么简单而强大的Python,以及Tornado(和这本书)正是为你准备的!

    安装:

    C:Program FilesRabbitMQ Server
    abbitmq_server-3.6.9sbin>pip3 install tornado
    Collecting tornado
      Downloading tornado-4.5.1-cp36-cp36m-win_amd64.whl (422kB)
        100% |████████████████████████████████| 430kB 16kB/s
    Installing collected packages: tornado
    Successfully installed tornado-4.5.1
    

    Python3.6上执行 pip3 install tornado 后即可安装成功

    简单示例:

    import tornado.ioloop
    import tornado.web
    
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            self.write("Hello, world")
    
    def make_app():
        return tornado.web.Application([
            (r"/", MainHandler),
        ])
    
    if __name__ == "__main__":
        app = make_app()
        app.listen(8888)
        tornado.ioloop.IOLoop.current().start()
    

    运行后,浏览器输入http://127.0.0.1:8888即可访问,显示Hello world。这个示例不使用任何Tornado的异步特性,看起来只是像个简单的聊天室。

    简单的Web服务

    1、应用示例:

    Tornado是一个编写对HTTP请求响应的框架。作为程序员,你的工作是编写响应特定条件HTTP请求的响应的handler。下面是一个全功能的Tornado应用的基础示例

    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)     # python hello.py --port=8000 指定运行端口默认8000 传入类型int
    
    class IndexHandler(tornado.web.RequestHandler):                    # 处理类
        def get(self):                                                  # get请求
            greeting = self.get_argument('greeting', 'Hello')         # 接收greeting参数,默认为Hello 不指定默认值当没有此参数时400错误
            self.write(greeting + ', friendly user!')                 # 返回的数据
    
    if __name__ == "__main__":
        # 这是真正使得Tornado运转起来的语句。首先,我们使用Tornado的options模块来解析命令行
        # 然后我们创建了一个Tornado的Application类的实例。传递给Application类__init__方法的最重要的参数是handlers。
        # 它告诉Tornado应该用哪个类来响应请求。
        tornado.options.parse_command_line()
        app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
    
        # 从这里开始的代码将会被反复使用:一旦Application对象被创建,我们可以将其传递给Tornado的HTTPServer对象,
        # 然后使用我们在命令行指定的端口进行监听(通过options对象取出。)
        # 最后,在程序准备好接收HTTP请求后,我们创建一个Tornado的IOLoop的实例。
        http_server = tornado.httpserver.HTTPServer(app)
        http_server.listen(options.port)
        tornado.ioloop.IOLoop.instance().start()
    

    直接运行程序或者指定端口:

    $ python hello.py --port=8000
    

    通过浏览器访问对应的端口服务,传入greeting参数获取不同的结果:

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

    参数handlers:

    让我们再看一眼hello.py示例中的这一行:

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

    这里的参数handlers非常重要,值得我们更加深入的研究。它应该是一个元组组成的列表,其中每个元组的第一个元素是一个用于匹配的正则表达式,第二个元素是一个RequestHanlder类。在hello.py中,我们只指定了一个正则表达式-RequestHanlder对,但你可以按你的需要指定任意多个。

    使用正则表达式指定路径:

    Tornado在元组中使用正则表达式来匹配HTTP请求的路径。(这个路径是URL中主机名后面的部分,不包括查询字符串和碎片。)Tornado把这些正则表达式看作已经包含了行开始和结束锚点(即,字符串"/"被看作为"^/$")。

    如果一个正则表达式包含一个捕获分组(即,正则表达式中的部分被括号括起来),匹配的内容将作为相应HTTP请求的参数传到RequestHandler对象中。我们将在下个例子中看到它的用法。

    2、更复杂的示例:

    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, int(width)))
            
    if __name__ == "__main__":
        tornado.options.parse_command_line()
        app = tornado.web.Application(
            handlers=[
                (r"/reverse/(w+)", ReverseHandler),          # 正则匹配访问url,调用不同的函数类
                (r"/wrap", WrapHandler)
            ]
        )
        http_server = tornado.httpserver.HTTPServer(app)
        http_server.listen(options.port)
        tornado.ioloop.IOLoop.instance().start()

    启动程序,这个程序是一个通用的字符串操作的Web服务端基本框架。到目前为止,你可以用它做两件事情。其一,到/reverse/stringGET请求将会返回URL路径中指定字符串的反转形式

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

    其二,到/wrapPOST请求将从参数text中取得指定的文本,并返回按照参数width指定宽度装饰的文本。下面的请求指定一个没有宽度的字符串,所以它的输出宽度被指定为程序中的get_argument的默认值40个字符。

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

      

    RequestHandler更多

    到目前为止,我们已经了解了RequestHandler对象的基础:如何从一个传入的HTTP请求中获得信息(使用get_argument和传入到getpost的参数)以及写HTTP响应(使用write方法)。除此之外,还有很多需要学习的,我们将在接下来的章节中进行讲解。同时,还有一些关于RequestHandler和Tornado如何使用它的只是需要记住。

    1、HTTP方法:

    截止到目前讨论的例子,每个RequestHandler类都只定义了一个HTTP方法的行为。但是,在同一个处理函数中定义多个方法是可能的,并且是有用的。把概念相关的功能绑定到同一个类是一个很好的方法。比如,你可能会编写一个处理函数来处理数据库中某个特定ID的对象,既使用GET方法,也使用POST方法。想象GET方法来返回这个部件的信息,而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)

    我们到目前为止只是用了GETPOST方法,但Tornado支持任何合法的HTTP请求(GETPOSTPUTDELETEHEADOPTIONS)。你可以非常容易地定义上述任一种方法的行为,只需要在RequestHandler类中使用同名的方法。下面是另一个想象的例子,在这个例子中针对特定frob ID的HEAD请求只根据frob是否存在给出信息,而GET方法返回整个对象:

    # 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())

    2、HTTP状态码:

    从上面的代码可以看出,你可以使用RequestHandler类的set_status()方法显式地设置HTTP状态码。然而,你需要记住在某些情况下,Tornado会自动地设置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)响应码。 

    3、自定义错误:

    当上述任何一种错误发生时,Tornado将默认向客户端发送一个包含状态码和错误信息的简短片段。如果你想使用自己的方法代替默认的错误响应,你可以重写write_error方法在你的RequestHandler类中。比如,代码清单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请求时,会得到下面的响应。一般来说,我们应该得到Tornado默认的错误响应,但因为我们覆写了write_error,我们会得到不一样的东西:

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

    补充 获取url传入参数,获取请求地址,请求客户ip,收到请求时间

    import tornado.ioloop
    import tornado.web
    
    
    class MainHandler(tornado.web.RequestHandler):
    
        def get(self,media):
            print(media)
            print(self.request.path)
            print(self.request.full_url())
            print(self.request.remote_ip)
            print(self.request.request_time())
            self.write('ok')
    
    def make_app():
        return tornado.web.Application([
            # (r"/", MainHandler),
            (r"^/download/(.*)", MainHandler,),
        ])
    
    if __name__ == "__main__":
        app = make_app()
        app.listen(8888)
        tornado.ioloop.IOLoop.current().start()
    

    获取json数据

    class MainHandler(RequestHandler):
        def post(self):
            print(self.request.arguments)
            param = self.request.body.decode('utf-8')
            prarm = json.loads(param)
            print(param)
            self.write('Ok')
    

      

     

    参考-《introduction to tornado

  • 相关阅读:
    C语言笔记
    js学习笔记
    Javascript学习笔记
    Java基础知识
    使用 StackExchange.Redis 封装属于自己的 RedisHelper
    StackExchange.Redis 使用资料
    .NET平台下Redis使用(三)【ServiceStack.Redis学习】
    .NET平台下Redis使用(二)【StackExchange.Redis学习】
    Redis 详解 (一) StackExchange.Redis Client
    .NET中使用Redis
  • 原文地址:https://www.cnblogs.com/lianzhilei/p/7053073.html
Copyright © 2020-2023  润新知