使用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通讯服务器到这里就结束了

 

posted on   双调  阅读(2224)  评论(3编辑  收藏  举报

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示