【问题标题】:Get current user Async in Tornado在 Tornado 中获取当前用户异步
【发布时间】:2015-06-14 19:35:39
【问题描述】:

当我使用 get_current_user() 时,我需要异步检查 Redis 中的一些内容(使用 tornado-redis)。

我正在做以下事情:

def authenticated_async(method):

    @gen.coroutine
    def wrapper(self, *args, **kwargs):
        self._auto_finish = False
        self.current_user = yield gen.Task(self.get_current_user_async)
        if not self.current_user:
            self.redirect(self.reverse_url('login'))
        else:
            result = method(self, *args, **kwargs) # updates
            if result is not None:
                yield result
    return wrapper

class BaseClass():

    @gen.coroutine
    def get_current_user_async(self,):

        auth_cookie = self.get_secure_cookie('user') # cfae7a25-2b8b-46a6-b5c4-0083a114c40e
        user_id = yield gen.Task(c.hget, 'auths', auth_cookie) # 16
        print(123, user_id)
        return auth_cookie if auth_cookie else None

例如,我想使用 authenticated_async 装饰器:

class IndexPageHandler(BaseClass, RequestHandler):

    @authenticated_async
    def get(self):
        self.render("index.html")

但我在控制台中只有 123

怎么了?如何解决?

谢谢!

更新

我已经用yield result 更新了代码。

auth_cookie 我有cfae7a25-2b8b-46a6-b5c4-0083a114c40e

然后我去终端:

127.0.0.1:6379> hget auths cfae7a25-2b8b-46a6-b5c4-0083a114c40e
"16"

所以,

user_id = yield gen.Task(c.hget, 'auths', auth_cookie)
print(123, user_id)

必须返回

123 16

但它返回一个 123

更新 1

class IndexPageHandler(BaseClass, RequestHandler):
    @gen.coroutine
    def get(self):
        print('cookie', self.get_secure_cookie('user'))
        user_async = yield self.get_current_user_async()
        print('user_async', user_async)
        print('current user', self.current_user)
        self.render("index.html",)

在控制台我有:

cookie b'cfae7a25-2b8b-46a6-b5c4-0083a114c40e'
123 
user_async b'cfae7a25-2b8b-46a6-b5c4-0083a114c40e'
current user None

【问题讨论】:

  • 如果被包装的方法本身是一个协程,则在从authenticated_async 的包装器(result = method(*args, **kwargs); if result is not None: yield result)调用它时必须让其屈服。不过,这不适用于IndexPageHandler。如果您进入 print 语句,看起来所有异步内容都在工作,而您只是从 c.hget 得到一个空结果(不管是什么)。如果不是这样,您能否更清楚地了解您的期望以及您所看到的?
  • @BenDarnell 我已经更新了帖子。
  • 没有装饰器可以工作吗?如果您直接在handler.get 中调用get_secure_cookiec.hget(或get_current_user_async)会怎样?
  • @BenDarnell 我更新了帖子
  • 您需要将get() 包裹在@gen.coroutine 中,并在调用get_current_user_async() 时使用yield

标签: python tornado


【解决方案1】:

get_secure_cookie() 返回一个字节串;因为打印出的 cookie 带有 b' 前缀,所以您必须在 Python 3 上。在 Python 3 上,tornado-redis 似乎需要 unicode 字符串而不是字节字符串;任何不是 unicode 字符串的输入都将使用 str() 函数转换为一个。这会添加上面看到的b' 前缀,因此您查询的是b'cfae7a25-2b8b-46a6-b5c4-0083a114c40e',而不是cfae7a25-2b8b-46a6-b5c4-0083a114c40e

解决方法是将cookie转换成str再发送到redis:auth_cookie = tornado.escape.native_str(auth_cookie)

【讨论】:

    【解决方案2】:

    看一下gen.Task的doc字符串:

    接受一个函数(和可选的附加参数)并运行它 这些参数加上 callback 关键字参数。

    c.hget 是否接受回调参数?如果没有,回调将抛出异常,future 不会被设置结果,因此 print 语句不会打印用户 id。

    【讨论】:

    【解决方案3】:

    答案在你的包装协程中。

            if result is not None:
                yield result
    

    你不想产生结果,而是想从协程中“返回”它。但是,由于 Python 不允许您使用来自生成器的非空返回,因此您需要将其作为 Tornado 可以解包的包装异常引发,并将结果传递给调用者 (get_current_user )

    if result is not None:
        raise gen.Return(result)
    

    完成后,您应该会发现它有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-08
      相关资源
      最近更新 更多