异步登录龙卷风

时间:2017-07-31 06:29:41

标签: python asynchronous tornado

我使用Tornado创建一个可以在同步方法上工作的登录页面。现在我想让它异步。那么我应该对以下代码做些什么改变:

import tornado.ioloop
import tornado.web
import http
import time

class BaseHandler(tornado.web.RequestHandler):
    def get_current_user(self):
        return self.get_secure_cookie("user")

class MainHandler(BaseHandler):
    def get(self):
        if not self.current_user:
            self.redirect("/login")
            return
        name = tornado.escape.xhtml_escape(self.current_user)
        self.write('<html>'
    '<head> '
    '<title>WELCOME  </title>'
    '</head>'
    '<body style="background:orange;"'

    '<div align="center">'
    '<div style="margin-top:200px;margin-bottom:10px;">'
    '<span style="width:500px;color:black;font-size:30px;font-weight:bold;">WELCOME </span>'
    '</div>'
    '<div style="margin-bottom:5px;">'"Hello, " + name)

class LoginHandler(BaseHandler):
    def get(self):
        self.write('<html><body><form action="/login" method="post">'
                   '<div><span style="width:100px;;height: 500px;color:black;font-size:60;font-weight:bold;">'
                   'LOGIN'
                   '<div><span style="width:100px;;height: 500px;color:purple;font-size:30;font-weight:bold;">'
                   'NAME <input type="text" name="name">'
                   '<div><span style="width:100px;height: 500px;color:purple;font-size:30;font-weight:bold;">PASSWORD</span><input style="width:150px;" type="password" name="password" id="password" value="">'
                   '</div>'                   
                   '<input type="submit" value="Sign in">'
                   '</form></body></html>')

    def post(self):
        self.set_secure_cookie("user", self.get_argument("name"))
        time.sleep(10)
        self.redirect("/")

application = tornado.web.Application([
    (r"/", MainHandler),
    (r"/login", LoginHandler),
], cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__")

application.listen(5000)
tornado.ioloop.IOLoop.current().start()

在我的代码中,我有三个类BaseHandlerMainHandlerLoginHandler。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:1)

一个简单的例子

Python 3.5 引入了 asyncawait 关键字(使用这些关键字的函数也称为“原生协程”)。有关详情,请参阅 the answer

我们为 Tornado 应用构建的每个基于类的视图都必须从 RequestHandler 中找到的 tornado.web 对象继承。

如果我们重写 prepare 方法,我们可以设置一些逻辑来运行,每当收到 request 时都会执行。

def tornado.web.RequestHandler.get_current_user(self) - 覆盖以确定当前用户,例如,cookie。

子类可以覆盖 get_current_user(),它会在第一次访问 self.current_user 时自动调用。 get_current_user() 每次请求只会被调用一次,并被缓存以备将来访问。

class BaseHandler(tornado.web.RequestHandler):
    def prepare(self):
        if self.get_argument("btn1", None) is not None:
            print("detected click on btn Profile")
            self.redirect("/profile")
            return

        if self.get_argument("btn2", None) is not None:
            print("detected click on btn Sources")
            self.redirect("/sources")
            return

        if self.get_argument("logout", None) is not None:
            self.clear_cookie("username")
            self.redirect("/")
            return

        if self.get_argument("btnSignIn", None) is not None:
            print("detected click on btnSignIn")
            self.redirect("/signin")
            return

    def get_current_user(self):
        a = self.get_secure_cookie("username")
        if a:
            return a.decode("utf-8")
        return None
class LoginHandler(BaseHandler):
    def get(self):
        self.render('login.html')

    def prepare(self):
        super().prepare()

    async def post(self):
        username = self.get_argument("username")
        password = self.get_argument("password")

        my_db = self.settings['db']
        collection = my_db.test

        val = await do_check_one(collection, username, password)

        if val is not None:
            self.set_secure_cookie("username", username)
            self.redirect("/profile")
        else:
            self.write('<h1>Wrong credentials</h1>')

为了更好地理解,请参阅:Simplest async/await example

async def do_check_one(my_collection, value1, value2):
    document = await my_collection.find_one({"name": value1, "password": value2})
    return document

main

选项在使用前必须用 tornado.options.define 定义,一般在模块的顶层。然后这些选项可以作为 tornado.options.options 的属性访问。

您的应用程序的 main() 方法不需要知道整个程序中使用的所有选项;它们都是在加载模块时自动加载的。但是,必须在解析命令行之前导入所有定义选项的模块。


define("port", default=8000, help="run on the given port", type=int)


if __name__ == '__main__':
    tornado.options.parse_command_line()

    client = motor.motor_tornado.MotorClient('localhost', 27017)
    db = client.test
    collection = db.test

    settings = {
        "template_path": os.path.join(os.path.dirname(__file__), "templates"),
        "static_path": os.path.join(os.path.dirname(__file__), "static"),
        "cookie_secret": "_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
        "login_url": "/login",
        "db": db,
        "debug": True,
        "xsrf_cookies": True
    }

    app = tornado.web.Application(
        handlers=[(r'/', MainHandler),
                  (r'/sources', SourceHandler),
                  (r'/login', LoginHandler),
                  (r'/signin', SigninHandler),
                  (r'/profile', ProfileHandler),
                  (r'/favicon.ico', tornado.web.StaticFileHandler, dict(path=settings['static_path'])),
                  ],
        **settings
    )
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    try:
        tornado.ioloop.IOLoop.instance().start()
        print('Server started...')
    except KeyboardInterrupt:
        print('Server has shut down.')

您的 main() 方法可以解析命令行或使用 parse_command_lineparse_config_file 解析配置文件:

tornado.options.parse_command_line()
# or
tornado.options.parse_config_file("/etc/server.conf")

答案 1 :(得分:0)

在此处使用async/await表示法,可能适合您的Python版本:

class BaseHandler(tornado.web.RequestHandler):
    async def get_current_user(self):
        return await some_async_operation()

    async def prepare(self):
        self.current_user = await self.get_current_user()

Tornado没有开箱即用地异步调用get_current_user,但它会使用异步prepare方法,因此您可以填充self.current_user

答案 2 :(得分:0)

不要打电话&#34;睡觉&#34;在龙卷风方法中:

http://www.tornadoweb.org/en/stable/faq.html

如果您希望暂停该方法一段时间以证明自己没有阻止,请添加from tornado import gen并尝试:

async def post(self):
    self.set_secure_cookie("user", self.get_argument("name"))
    yield gen.sleep(10)
    self.redirect("/")

或者在Python 2中:

@gen.coroutine
def post(self):
    self.set_secure_cookie("user", self.get_argument("name"))
    yield gen.sleep(10)
    self.redirect("/")