装饰模式 - python tornado中如何给每个服务器请求动态加上装饰器?
PHP中文网
PHP中文网 2017-04-17 16:48:32
0
2
246
PHP中文网
PHP中文网

认证高级PHP讲师

reply all(2)
Peter_Zhu

tornado provides methods such as prepare and finish in RequestHandler. prepare is called before the framework calls get/post/... these methods. finish is called by the framework when the response is finally written back. So you can use this to implement functions similar to middleware in django. For example, login check, permission verification, and response modification results can all be completed in middleware.

class Middleware(object):
    def process_request(self, handler):
        pass
        
    def process_response(self, handler):
        pass
        

def prepare(self):
    for middle in self.application.middleware:
        middle.process_request(self)
    super(MyRequestHandler, self).prepare()            

def finish(self):
    for middle in self.application.middleware:
        middle.process_response(self)
        
        
                                                                    
伊谢尔伦

Must be a metaclass, used to control the creation of classes.

Sample code, assuming that get_user能返回用户名,即类B is not logged in after logging in:

# -*- coding: utf-8 -*-

import functools


class HttpError(Exception):
    pass


def logined(func):
    @functools.wraps(func)
    def _wrapper(self, *args, **kwargs):
        if self.user:
            return func(self, *args, **kwargs)
        # Or, redirect.
        raise HttpError(403)
    return _wrapper


class MetaWrapWithLogin(type):

    def __new__(cls, name, bases, attrs):
        need_login = list()
        if 'need_login' in attrs:
            need_login.extend(list(attrs['need_login']))
        for method in need_login:
            if method in attrs:
                attrs[method] = logined(attrs[method])
        return type.__new__(cls, name, bases, attrs)


class Base(object):

    @property
    def user(self):
        return self.get_user()

    def get_user(self):
        pass

    def get(self):
        raise HttpError(404)

    def post(self):
        raise HttpError(404)


class A(Base):
    __metaclass__ = MetaWrapWithLogin
    need_login = ['get', 'post']

    def get_user(self):
        return 'foo'

    def get(self):
        print('{0} get'.format(self.__class__.__name__))

    def post(self):
        print('{0} post'.format(self.__class__.__name__))


class B(Base):
    __metaclass__ = MetaWrapWithLogin
    need_login = ['post']

    def get(self):
        print('{0} get'.format(self.__class__.__name__))

    def post(self):
        print('{0} post'.format(self.__class__.__name__))


if __name__ == '__main__':
    a = A()
    a.get()
    a.post()

    print('\n{0}\n'.format('-' * 10))

    b = B()
    b.get()
    b.post()

Output:

A get
A post

----------

B get
Traceback (most recent call last):
  File "test.py", line 88, in <module>
    b.post()
  File "test.py", line 16, in _wrapper
    raise HttpError(403)
__main__.HttpError: 403

Then follow this idea and transform it yourself.


Decorator version:

# -*- coding: utf-8 -*-

import functools


def login_decorator(func):
    @functools.wraps(func)
    def _wrapper(self, *args, **kwargs):
        if hasattr(self, 'user') and self.user:
            return func(self, *args, **kwargs)
        # Or, redirect.
        raise HttpError(403)
    return _wrapper


def add_to_methods(decorator, *methods):
    def wrap_method(cls):
        for method in methods:
            if hasattr(cls, method):
                setattr(cls, method, decorator(getattr(cls, method)))
        return cls
    return wrap_method


class HttpError(Exception):
    pass


@add_to_methods(login_decorator, 'post')
class A(object):

    def get(self):
        print('{0} get'.format(self.__class__.__name__))

    def post(self):
        print('{1} post'.format(self.__class__.__name__))


if __name__ == '__main__':
    a = A()
    a.get()
    a.post()

Output:

A get
Traceback (most recent call last):
  File "need.py", line 42, in <module>
    a.post()
  File "need.py", line 12, in _wrapper
    raise HttpError(403)
__main__.HttpError: 403
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!