3

ID とアクセス キーの安全な Cookie を使用して承認されたアクセスをテストする多数の tornado.web.RequestHandler クラスがあります。gen.Task を使用して、インライン コールバックで非同期に mongodb にアクセスします。非同期性のため、反復コードを除外する方法を見つけるのに苦労しています。これどうやってするの?

class MyHandler(RequestHandler):
    @tornado.web.asynchronous
    @gen.engine
    def get(self):
        id = self.get_secure_cookie('id', None)
        accesskey = self.get_secure_cookie('accesskey', None)
        if not id or not accesskey:
            self.redirect('/a_public_area')
            return
        try:
            # convert to bson id format to access mongodb
            bson.objectid.ObjectId(id)
        except:
            # if not valid object id
            self.redirect('/a_public_area')
            return
        found_id, error = yield gen.Task(asyncmong_client_inst.collection.find_one, 
            {'_id': id, 'accesskey': accesskey}, fields={'_id': 1})
        if error['error']:
            raise HTTPError(500)
            return
        if not found_id[0]:
            self.redirect('/a_public_area')
            return

        # real business code follows

上記を、おそらく HTTP ステータス コードを生成する関数に組み込みたいと思います。

4

3 に答える 3

3

Tornado にはデコレータがあり@tornado.web.authenticatedます。使ってみましょう。

class BaseHandler(RequestHandler):
   def get_login_url(self):
        return u"/a_public_area"

    @gen.engine #Not sure about this step
    def get_current_user(self):
        id = self.get_secure_cookie('id', None)
        accesskey = self.get_secure_cookie('accesskey', None)
        if not id or not accesskey:
            return False

        #Are you sure need this? 
        try:
            # convert to bson id format to access mongodb
            bson.objectid.ObjectId(id)
        except:
            # if not valid object id
            return False

        #I believe that you don't need asynchronous mongo on auth query, so if it's not working - replace it with sync call
        found_id, error = yield gen.Task(asyncmong_client_inst.collection.find_one, 
            {'_id': id, 'accesskey': accesskey}, fields={'_id': 1})

        if error['error']:
            raise HTTPError(500)

        if not found_id[0]:
            return False

        return found_id


class MyHandler(BaseHandler):
    @tornado.web.asynchronous
    @tornado.web.authenticated
    @gen.engine
    def get(self):
        # real business code follows

どこでも使用gen- 良い習慣ではありません。この世界を大きなスパゲッティに変えることができます。考えてみてください。

于 2012-07-26T08:52:13.557 に答える
3

おそらくデコレータ(テストされていないか、いくつかのアイデアのみ)

def sanitize(fn):
    def _sanitize(self, *args, **kwargs):
        id = self.get_secure_cookie('id', None)
        accesskey = self.get_secure_cookie('accesskey', None)
        if not id or not accesskey:
            self.redirect('/a_public_area')
            return
        try:
            # convert to bson id format to access mongodb
            bson.objectid.ObjectId(id)
        except:
            # if not valid object id
            self.redirect('/a_public_area')
            return
        return fn(self, *args, **kwargs)
    return _sanitize

check_errors をビジネスロジックで動作させることができるかどうかはわかりません..しかし多分..

def check_errors(fn):
   def _check_errors(*args, **kwargs)
      found_id, error = fn(*args, **kwargs)
      if error['error']:
         raise HTTPError(500)
         return
      if not found_id[0]:
         self.redirect('/a_public_area')
         return
   return _check_errors

それから

class MyHandler(RequestHandler):
    @tornado.web.asynchronous
    @gen.engine
    @sanitize
    @check_errors #..O.o decorators
    def get(self):
        found_id, error = yield gen.Task(asyncmong_client_inst.collection.find_one, 
              {'_id': id, 'accesskey': accesskey}, fields={'_id': 1})
        return found_id, error
于 2012-07-26T06:12:00.390 に答える
2

gen.Task に関するこの一般的な問題に対処したいと思います。それは、コードの因数分解が不可能であるか、非常に不器用であるということです。

get() または post() メソッド内でのみ「yield gen.Task(...)」を実行できます。get() で別の関数 foo() を呼び出し、foo() で作業を行いたい場合は、すべてをジェネレーターとして記述し、扱いにくい方法でそれらを連鎖させたい場合を除き、それはできません。プロジェクトが大きくなるにつれて、これは大きな問題になるでしょう。

これははるかに優れた代替手段です: https://github.com/mopub/greenlet-tornado

これを使用して、大規模な同期コードベースをほとんど変更せずに Tornado に変換しました。

于 2012-11-21T23:04:41.503 に答える