【问题标题】:How to store database session in Tornado RequestHandler如何在 Tornado RequestHandler 中存储数据库会话
【发布时间】:2017-12-13 15:13:50
【问题描述】:

我正在为 Tornado 中的用户会话管理实施一个安全的 cookie 方案。通过 SQLAlchemy 访问用户的详细信息。目前我需要打开两个数据库会话:一个用于验证用户在身份验证期间是否存在,另一个用于查询模型的其他部分。像这样的:

class BaseHandler(tornado.web.RequestHandler):
    def get_current_user(self):
        user_id = self.get_secure_cookie('user')
        if not user_id:
            return None
        with model.session_scope() as session:
            user = session.query(model.AppUser).get(user_id)
            if not user:
                return None
            session.expunge(user)
        return user

class OtherHandler(BaseHandler):
    @tornado.web.authenticated
    @gen.coroutine
    def put(self, ob_id):
        with model.session_scope() as session:
             other = session.query(model.Other).get(ob_id)
             session.merge(self.current_user)
             if not user.can_view(other):
                 raise AuthzError
             yield self.some_operation(other)
        self.finish()

如果我不必使用merge 将用户对象带回会话中,那就太好了。是否有一种安全的方法可以将数据库会话和persistentuser 对象存储在处理程序中?我正在考虑做这样的事情:

class BaseHandler(tornado.web.RequestHandler):
    def prepare(self):
        self.session = model.Session()
        user_id = self.get_secure_cookie('user')
        if user_id:
            self.current_user = session.query(model.AppUser).get(user_id)

    def finish(self, chunk=None):
        try:
            return super().finish(chunk)
        finally:
            self.session.commit()

    def send_error(self, status_code=500, **kwargs):
        try:
            return super().send_error(status_code=status_code, **kwargs)
        finally:
            self.session.rollback()

问题:

  1. 即使使用异步代码(@gen.coroutineyield),将 session(或其他任何内容)存储在 self 中是否安全
  2. 我在finishsend_error 中关闭会话的方式是否稳健?我想确保我没有任何僵尸会话。

【问题讨论】:

  • 与您的问题无关,但是,我认为使用 Tornado 中的 SQLAlchemy 查询 db 会阻塞服务器。

标签: python session asynchronous sqlalchemy tornado


【解决方案1】:

我在完成和 send_error 中关闭会话的方式是否可靠?我想确保我周围没有任何僵尸会话

您可以使用on_finishon_connection_close

def on_finish(self):
    if self.get_status_code() >= 500:
        self.session.rollback()
    else:
        self.session.commit()

请注意,可能存在更好的方法来区分错误响应。也看看讨论 - https://github.com/tornadoweb/tornado/issues/517

即使使用异步代码(@gen.coroutine 和 yield),将会话(或其他任何内容)存储在 self 中是否安全?

RequestHandler 对象是为每个请求创建的,它不是共享的。在这种情况下,异步不会使代码更容易(我认为)将数据存储在“self”中。

【讨论】:

  • 我不确定on_finish 是否足够强大。它是called by finish,它不进行任何异常处理以确保真正调用on_finish。感谢您提供有关on_connection_close 的提示。假设我坚持使用finishon_finish,我可能也应该覆盖它。如果 Tornado 有一个明确定义的资源清理方法就好了:/
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-23
相关资源
最近更新 更多