Tornado - Введение в асинхронность
Primary tabs
Доброго времени суток, сегодня поговорим о Tornado - это асинхронный (неблокирующий) веб-фреймворк. О самих асинхронных серверах и об архитектуре в общем мы говорили тут.
Также об Async Web есть запись видеовстречи iff: https://www.youtube.com/watch?feature=pl...
Итак, Tornado.
Документация к фреймворку основанна на встроенной системе документации python. На момент написания статьи актуальной версией Tornado является 3.2, ну и конечно мы используем python3.
Из-за скудной документации приходится часто рыться в исходниках, чтобы понять как работать с данным чудом, поэтому я буду ждать вопросов от тех, кто выберет данный фреймворк и сервер для своих проектов. В этой статье, я постараюсь рассказать о самых основных проблемных вопросах в Tornado.
Для того чтобы было понятно тем, кто не знаком с Tornado, я приведу типичный код из документации, в котором будет создан самый простой http-сервер, обрабатывающий http запросы.
class MainHandler(RequestHandler): # класс-обработчик запроса, он будет обрабатывать поступивший url def get(self): # переобределяем метод GET self.write("ololo") # записываем в ответ "ololo" # на этом обработка запроса завершается class TestHandler(RequestHandler): def initialize(self, database): # здест мы передаём при связке с url параметр self.database = database # см. ниже def get(self): ... class HiamHandler(RequestHandler): def post(self, username): # параметр в url присутсвует в параметрах функции обработки запроса ... app_settings = { # здесь популярные настройки, не нужно обращать на них внимания 'autoreload': True, 'debug': True, 'gzip': False, 'serve_traceback': True, # True, if Debug #'log_function': SOME_LOG_Function, #'default_handler_class': SOME_VALUE, #'default_handler_args': SOME_VALUE, 'cookie_secret': "DebuG)", #'login_url': "SOME_LOGIN_URL", 'xsrf_cookies': True, #'autoescape': None, 'compiled_template_cache': False, # False, if Debug 'template_path': "SOME PATH", #'template_loader': SOME_VALUE, 'static_hash_cache': False, # False, if Debug 'static_path': "SOME PATH", 'static_url_prefix': "/static/", } if __name__ == "__main__": # далее код инициализации и запуска сервера application = tornado.web.Application([ # создаём наше приложение - сервер (r"/", MainHandler), # тут ставим в соответсвие класс-обработчик запроса и url (r"/test/", TestHandler, dict(database=database)), # возможно также # передавать дополнительный параметр (r"/hwoiam/(.*)", HiamHandler), # параметры url определяются регулярным # выражением как в других фреймворках ], **app_settings) # словарь с настройками application.listen(8888) # указываем порт, который будем слушать tornado.ioloop.IOLoop.instance().start() # запускаем основную петлю задач, # что необходимо при асинхроной архитектуре
Это почти стандартный скелет для реализации собственного http сервера, более подробно смотрите документацию, для самых элементарных вещей она достаточно понятна: http://www.tornadoweb.org/en/stable/docu...
--- Грабля 1: Первое что нужно понять, что тут почти всё надо делать ручками. Для того чтобы использовать встроенную систему аутентификации нужно переопределить функцию get_current_user,а для защиты от XSRF достаточно следовать инструкциям, но у меня не всегда работала их система с JSON поэтому я переопределил функцию проверки так:
class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): # реализуем свою систему аутентификации #return None def check_xsrf_cookie(self): # эта переопределённая функция проверки xsrf токена token = (self.get_argument("_xsrf", None) or self.request.headers.get("X-Xsrftoken") or self.request.headers.get("X-Csrftoken")) if not token: raise tornado.web.HTTPError(403, "'_xsrf' argument missing from POST") else: try: token = tornado.escape.json_decode(token) except ValueError: token = token if self.xsrf_token != token: raise tornado.web.HTTPError(403, "XSRF cookie does not match POST argument")
После, для тех обработчиков для которых нужна аутентификация и проверка xsrf токена я применял наследование от BaseHandler.
---Грабля 2, она же главная. Это работа с асинхронностью, собственно понимание вопросав, связанных с асинхронной архитектурой и необходимо чтобы дальше продолжить читать материал. А проблема с пониманием того, как с помощью Tornado использовать фикши асинхронной архитектуры. Это будет цикл отдельных заметок, но сегодня я расскажу о самом простом способе - это переадресация задачи на другой сервер))) об этом говорилось на встрече iff. посвящённой асинхроному вебу. Почему так? - Это самый простой способ работы с блокирующими вызовами, и он прекрасно реализован в фраемворке.
Итак:
- К нам приходит запрос
- Что-то делаем, блокирующие вызовы и длительные вычисления реализовываем на другом сервере
- Делаем средствами фреймворка асинхронный запрос
Пример (прям из документации):
class GenAsyncHandler(RequestHandler): @gen.coroutine # с помощью декоратора объявляем # метод асинхронным def get(self): http_client = AsyncHTTPClient() # создаём асинхронный клиент response = yield http_client.fetch("http://example.com") # делаем неблокирующий запрос #после этого обработка запроса прерывается и выполняются #другие задачи из очереди #когда сервер, выполняющий наши долгие вычисления или обращение к диску #ответит, и торнадо получит результат #обработка продолжится в порядке очереди do_something_with_response(response) self.render("template.html") # завершаем обработку
Итак, теперь в принципе понятна архитектура Tornado и далее поговорим о том, как создавать собственные асинхронные обработчики средствами Tornado. Но это потом....
- Log in to post comments
- 9298 reads