• 使用tornado,我们可以做什么?


    以下介绍都是建立在python2.x的基础上面,tornado使用任意版本皆可。

    如果我们需要对外提供一个http server(web api)/websocket server时,我们都可以使用tornado,以下是一个基于tornado的rest的应用简介。

    当我们下载好了tornado以后,可以按照tornado的文档demo,复制一份监听代码过来,代码如下:

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

    这一段代码在运行时就已经可以开始监听并返回信息了,然后开始按照rest的规范开始改写,我们首先需要对url的path进行定位,根据path执行相对应的代码,则有了以下代码:

    import os.path
    import tornado.escape
    import tornado.ioloop
    import tornado.options
    import tornado.web
    import tornado.websocket
    import tornado.httpserver
    import tools
    import applogic
    from config import config
    
    class Application(tornado.web.Application):
        def __init__(self):
            handlers = [
                (r"/.*?", WebHandler),
            ]
            settings = dict(
                cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
                template_path=os.path.join(os.path.dirname(__file__), "templates"),
                static_path=os.path.join(os.path.dirname(__file__), "static"),
                xsrf_cookies=False
            )
            tornado.web.Application.__init__(self, handlers, **settings)
    
    class WebHandler(tornado.web.RequestHandler):
        def get(self):
            path = self.request.path
            command = path[path.rfind('/') +1:]
            result = applogic.execute(self, command, self.get_argument)
            if result:
                to_message = tools.dumps(result)
                self.write(to_message)
    
    
        def post(self):
            path = self.request.path
            command = path[path.rfind('/') +1:]
            obj = tools.loads(self.request.body)
            result = applogic.execute(self, command, obj)
            if result:
                to_message = tools.dumps(result)
                self.write(to_message)
    
    def main():
        app = Application()
        http_server = tornado.httpserver.HTTPServer(app)
        http_server.bind(config.default['main_port'], config.default['host'])
        tornado.ioloop.IOLoop.instance().start()
    View Code

    我们对path做了最后一级目录的截取,由于客观原因,多级目录的则需要看客们自行实现。

    applogic是我们的具体的逻辑代码门面类,因为是脚本语言的关系,所以这里使用一个相对巧妙的ioc,代码如下:

    def execute(handler, command, obj):
        if main_map.has_key(command):
            result = main_map[command](handler, obj)
            if result:
                response.send(handler, result)
        else:
            handler.send_error(404)
    
    
    def create(handler, obj):
        flag = papercache.push(obj)
        result = {}
        if flag:
            result = {
                'code':0
            }
        else:
            result = {
                'code':1,
                'errorMsg':'param is error'
            }
        return result
    
    def grab(handler, obj):
        id = obj.has_key('id') and obj['id'] or None
        result = {
            'code':1,
            'errorMsg':'redpaper is empty',
            'money':0
        }
        if id:
            money = papercache.pop_queue(id)
            if money:
                result = {
                    'money' : money,
                    'code': 0
                }
        return result
    
    
    main_map = {
        'create':create,
        'grab':grab
    }
    View Code

    我们将具体的执行逻辑,放在定义好的function里面,然后将function的引用放在一个字典里面,然后根据command(最后一级目录对应的字符串),来执行具体的代码。

    我们将返回的数据做了一个封装,因为实际应用里面的数据格式,可能采用的是json,或者是其它自定义的协议,所以我们有一个response的封装,代码如下:

    def send(handler, obj):
        if type(handler) is not None:
            obj = tools.dumps(obj)
            handler.write(obj)
    View Code

    tools的代码如下:

    import json
    
    
    def dumps(obj):
        obj = toUnicode(obj)
        if obj:
            obj = json.dumps(obj)
            obj = str(obj)
        return obj
    
    def loads(obj):
        if obj:
            obj = json.loads(str(obj))
            obj = toUtf8(obj)
        return obj
    View Code

    因为可能存在中文的关系,所以加了一个Utf8的转换,,基于websocket的也是同理,则在监听的时候,使用WebSocketHandle,代码如下:

    import os.path
    import tornado.escape
    import tornado.ioloop
    import tornado.options
    import tornado.web
    import tornado.websocket
    import tornado.httpserver
    import tools
    import applogic
    from config import config
    
    class Application(tornado.web.Application):
        def __init__(self):
            handlers = [
                (r"/web", MainHandler)
                (r"/.*?", WebHandler),
            ]
            settings = dict(
                cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
                template_path=os.path.join(os.path.dirname(__file__), "templates"),
                static_path=os.path.join(os.path.dirname(__file__), "static"),
                xsrf_cookies=False
            )
            tornado.web.Application.__init__(self, handlers, **settings)
    
    class MainHandler(tornado.websocket.WebSocketHandler):
        def allow_draft76(self):
            return True
    
        def open(self):
            token = self.get_cookie('token')
            if not token:
                print "long not token"
                self.close()
            else:
                print('connect')
    
        def on_close(self):
            print('close');
    
        def on_message(self, message):
            obj = tools.loads(message)
            command = obj.has_key('command') and obj['command'] or None
            body = obj.has_key('body') and obj['body'] or None
            result = applogic.execute(self, command, body)
            if result:
                to_message = tools.dumps(result)
                self.write(to_message)
            return
    
    class WebHandler(tornado.web.RequestHandler):
        def get(self):
            path = self.request.path
            command = path[path.rfind('/') +1:]
            result = applogic.execute(self, command, self.get_argument)
            if result:
                to_message = tools.dumps(result)
                self.write(to_message)
    
    
        def post(self):
            path = self.request.path
            command = path[path.rfind('/') +1:]
            obj = tools.loads(self.request.body)
            result = applogic.execute(self, command, obj)
            if result:
                to_message = tools.dumps(result)
                self.write(to_message)
    
    def main():
        app = Application()
        http_server = tornado.httpserver.HTTPServer(app)
        http_server.bind(config.default['main_port'], config.default['host'])
        tornado.ioloop.IOLoop.instance().start()
    View Code

    可能你们会觉得怎么多了个command和body出来了,因为我的通讯协议是假定{"command":"", "body":""},这样的json格式。

    那一个简易的基于python的rest服务和websocket通讯服务器到这里就结束了

    本人对代码不做任何知识产权限制,也不保证所有的代码皆为原创。
  • 相关阅读:
    开发工具
    CPU知识
    GMAP.NET
    vtordisp
    Hadoop HBase 配置 安装 Snappy 终极教程
    asp.net Vs访问正常,iis访问出现各种问题的部分处理方法
    MVC项目小结:动态菜单
    视频的采集和动态显示
    《编程之美》
    Nginx实现简单的负载均衡web访问
  • 原文地址:https://www.cnblogs.com/selfteam/p/4931256.html
Copyright © 2020-2023  润新知