首页 > 学院 > 开发设计 > 正文

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

2019-11-14 16:56:16
字体:
来源:转载
供稿:网友

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

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

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

import tornado.ioloopimport tornado.webclass 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.pathimport tornado.escapeimport tornado.ioloopimport tornado.optionsimport tornado.webimport tornado.websocketimport tornado.httpserverimport toolsimport applogicfrom config import configclass 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 resultdef 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 resultmain_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 jsondef dumps(obj):    obj = toUnicode(obj)    if obj:        obj = json.dumps(obj)        obj = str(obj)    return objdef loads(obj):    if obj:        obj = json.loads(str(obj))        obj = toUtf8(obj)    return obj
View Code

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

import os.pathimport tornado.escapeimport tornado.ioloopimport tornado.optionsimport tornado.webimport tornado.websocketimport tornado.httpserverimport toolsimport applogicfrom config import configclass 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)        returnclass 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通讯服务器到这里就结束了

 


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表