Tornado #4 支持restful风格API(利用猴子补丁)

文中所指的restful风格路由指:访问/user/123,可以进入/user路由,并获取id=123。
Tornado本身不支持,访问/user/123会返回404。

在项目中创建一个文件 monkeypatch.py:


import re
from tornado.routing import PathMatches
from tornado.web import RequestHandler, HTTPError
from tornado.util import basestring_type
from tornado.escape import url_unescape, _unicode

VALID_PARAM_TYPE = ['str', 'int', 'float']

def patch_route_restful():
    '''
    猴子补丁,目的是支持 GET /user/123 形式的restful风格路由
    :return:
    '''

    def __init__(self, path_pattern):
        if isinstance(path_pattern, basestring_type):
            self.param_type = None
            self.param_name = None
            if not path_pattern.endswith('$'):
                # MONKEYPATCH 支持<int:uid>形式结尾的匹配
                param_pattern = re.compile(r'<(.+?):(.+?)>$')
                if re.search(param_pattern, path_pattern):
                    self.param_type, self.param_name = re.search(param_pattern, path_pattern).groups()
                    if self.param_type not in VALID_PARAM_TYPE:
                        raise SyntaxError('Unsupport param type')
                    path_pattern = re.sub(param_pattern, r'(\w+)$', path_pattern)
                else:
                    path_pattern += '$'

            self.regex = re.compile(path_pattern)
        else:
            self.regex = path_pattern

        assert len(self.regex.groupindex) in (0, self.regex.groups), \
            ("groups in url regexes must either be all named or all "
             "positional: %r" % self.regex.pattern)

        self._path, self._group_count = self._find_groups()

    def _unquote_or_none(s):
        """None-safe wrapper around url_unescape to handle unmatched optional
        groups correctly.

        Note that args are passed as bytes so the handler can decide what
        encoding to use.
        """
        if s is None:
            return s
        return url_unescape(s, encoding=None, plus=False)

    def match(self, request):
        match = self.regex.match(request.path)

        if match is None:
            return None
        if not self.regex.groups:
            return {}

        path_args, path_kwargs = [], {}

        # Pass matched groups to the handler.  Since
        # match.groups() includes both named and
        # unnamed groups, we want to use either groups
        # or groupdict but not both.
        if self.regex.groupindex:
            path_kwargs = dict(
                (str(k), _unquote_or_none(v))
                for (k, v) in match.groupdict().items())
        else:
            # MONKEYPATCH 处理参数
            if match.groups() and match.groups()[0]:
                param_val = _unquote_or_none(match.groups()[0])
                try:
                    param_val = eval(self.param_type + '(' + param_val.decode('utf-8') + ')')
                except:
                    return None
                path_kwargs = {self.param_name: param_val}
            else:
                path_args = [_unquote_or_none(s) for s in match.groups()]

        return dict(path_args=path_args, path_kwargs=path_kwargs)

    def decode_argument(self, value, name=None):
        """Decodes an argument from the request.

        The argument has been percent-decoded and is now a byte string.
        By default, this method decodes the argument as utf-8 and returns
        a unicode string, but this may be overridden in subclasses.

        This method is used as a filter for both `get_argument()` and for
        values extracted from the url and passed to `get()`/`post()`/etc.

        The name of the argument is provided if known, but may be None
        (e.g. for unnamed groups in the url regex).
        """
        try:
            if type(value) != bytes:
                return value
            return _unicode(value)
        except UnicodeDecodeError:
            raise HTTPError(400, "Invalid unicode in %s: %r" %
                            (name or "url", value[:40]))

    PathMatches.__init__ = __init__
    PathMatches.match = match
    RequestHandler.decode_argument = decode_argument

再在初始化app前使用:

import tornado.web
from app.lib.monkeypatch import patch_route_restful

patch_route_restful()

def make_app():
    return tornado.web.Application(routes, db=db)

if __name__ == "__main__":
    app = make_app()
    # more code

这时,路由就支持restful风格了。

可以定义路由和handler如下:

import tornado.web

class UserHandler(tornado.web.RequestHandler):
    def get(self, uid):
        if uid:
            # 返回一个指定id的
        else:
            # 返回多个

routes = [(r'/user/<int:uid>', UserHandler)]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容

  • 引言 以Django为代表的python web应用部署时采用wsgi协议与服务器对接(被服务器托管),而这类服务...
    大熊_7d48阅读 2,035评论 0 3
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • 红日初升起 红纱般的霞光 罩在已醒转的城市上空 开始编程一天的美图 湛蓝的天际间 正翱翔着一架机鹰 在云锦的海洋航...
    六月天气阅读 455评论 20 40
  • 星期五 天气晴 今天语文第一单元考试,反应了孩子这一单元的学习情况。从今天的考试情况来看,整体来说还算可以...
    宝贝亲子成长日记阅读 230评论 2 2
  • 电影《至爱梵高》在影院热映的时候,我没有去看,并非不感兴趣,也不是抽不出时间,而是害怕,害怕共享一个影院空间的其他...
    姝写光影阅读 854评论 1 5