Tornado python что это
Перейти к содержимому

Tornado python что это

  • автор:

Django, Flask или Tornado: какой Python-фреймворк выбрать новичку

Django, Flask или Tornado: какой Python-фреймворк выбрать новичку главное изображение

Django, Flask и Tornado — самые актуальные и при этом наиболее популярные Python-фреймворки. В этой статье CTO wemake.services Никита Соболев сравнивает их возможности и пытается помочь читателю выбрать лучший инструмент.

Зачем нужны фреймворки

Фреймворки повышают скорость написания кода и позволяют сосредоточиться на логике приложения, а не на написании базовых функций. Это наборы различных пакетов и модулей, которые помогают программисту в тысяче нюансов: например, в работе с базами данных, локалями, валидацией, шаблонизацией, обработкой ошибок или защитой программы.

Основное преимущество Python перед другими языками программирования — возможность быстро писать код. Если распространить это суждение на фреймворки, то их главная задача — дать возможность сэкономить время на написании простых команд, что существенно повышает скорость разработки.

Хекслет для начинающих: Попробовать обучение на Хекслете вы можете на Подготовительном курсе по основам Python. Теория и практика в браузере, вебинары, лайвкодинг, помощь наставника

Сравним Django, Flask и Tornado в нескольких категориях: простота входа, производительность, гибкость и асинхронность.

  • Django — самый популярный Python-фреймворк, который используют разработчики в Pinterest, Dropbox, Spotify, The Washington Post и других компаниях. На сегодняшний день сообщество Django включает более 11 тыс. разработчиков из 166 стран мира.
  • Flask — это микрофреймворк для разработки на Python минималистичных каркасов веб-приложений, который предоставляет базовые возможности, а сами приложения реализуют какой-то функционал. С его помощью можно создавать небольшие приложения, для которых не нужен широкий спектр возможностей большого фреймворка — он представляет собой скелет, на который можно установить то, что нужно разработчику.
  • Tornado — сравнительно быстрый веб-фреймворк, который может обрабатывать тысячи одновременных постоянных подключений. Обычно он используется для веб-сокетов и других приложений, требующих долговременного соединения с каждым пользователем.

Удобство для новичков

В случае с фреймворками удобство для новичков определяется в первую очередь наличием подробной документации и легкостью интеграции, а не внешней простотой интерфейса. Найти подробный гайд для новичков и интегрировать разные сложные компоненты (аутентификацию, базу данных, кэширование) — распространенная проблема.

Flask и Tornado выглядят проще, чем Django, но страдают от отсутствия понятной документации. Про Tornado, среди прочего, мало материалов. Материалов о Django, напротив, очень много, а вопрос интеграции в нем решается внесением правок в конфигурационный файл. Чтобы выполнить сложную интеграцию во Flask или Tornado, нужно написать много кода. Это нетривиальная задача и в ней новички часто ошибаются.

Новичкам можно начинать с Flask — это самый простой Python-фреймворк, который подходит только для простых приложений. На его примере можно изучить жизненный цикл вопросов-ответов, которые проходят request и response. Кроме того, с его помощью масштабировать простые приложения проще, чем в Django. Tornado стоит использовать, если ваше приложение использует WebSocket или серверную часть NoSQL. Он тоже достаточно минималистичный, но более узконаправленный, чем Flask или Django.

Как только вы доберетесь до интеграции сложных компонентов или начнете разрабатывать многостраничные приложения, лучше перейти на Django. В этом фреймворке есть некоторый барьер сложности, но он одноразовый — нужно разобраться со связями между компонентами. Однако при работе с большими и сложными приложениями в этом фреймворке отпадают все вопросы интеграции. Кроме того, при правильном обращении Django может выглядеть также просто, как Flask — вот наглядный пример .

Если говорить о сообществе, то, помимо документации и туториалов, о Django есть подкасты, рассылки и конференции. У Flask и Tornado сообщества значительно меньше — в том числе потому, что они больше подходят для небольших проектов.

Читайте также: Как сохранять фокус на протяжении всего обучения: советы от Хекслета

Производительность

Производительность фреймворков часто оценивается количеством «хэллоуворлдов в секунду»: например, так проверяют количество соединений, которые сервис может держать одновременно, или скорость ответов. Это чисто теоретические измерения, которые никак не отражают реальную производительность.

Код на Python сравнительно медленный и потребляет много ресурсов — производительности уровня Rust в этом языке добиться не удастся. Как говорилось выше, этот показатель на Python определяется скоростью написания кода, поэтому рассмотрим фреймворки с этой точки зрения.

Благодаря простой интеграции, а также широкому выбору библиотек и компонентов, Django с большим отрывом побеждает Flask и Tornado. В последних решения костыльные и собирать их нужно по отдельным элементам, что сильно увеличивает время работы над сервисом.

Гибкость

Согласно определению фреймворк — набор рамок (фреймов), которые предлагают определенный способ выполнить определенное действие. Поэтому в случае с фреймворком гибкость — скорее недостаток, чем преимущество.

Во Flask гибкость сравнительно высокая: например, он позволяет создавать и использовать глобальные объекты, а также контекст треда для сложения промежуточных объектов. Меньше всего гибкости в Django, а Tornado находится где-то посередине между ними. В пользу Django говорит и то, что все приложения на этом фреймворке получаются одинаковыми, а на Flask — сильно отличаются друг от друга.

Асинхронность

Python и его библиотеки изначально не предназначены для асинхронного программирования, поэтому использование async/await создает дополнительную сложность при написании кода. Эти функции недостаточно просто добавить в код — их нужно еще правильно написать. Это требует дополнительного времени и снижает производительность.

В Django есть инструмент, который позволяет сделать код асинхронным при смене класса воркера jUnicorn на jevent . В зависимости от ситуации такой подход позволяет выиграть в производительности от 10% до 100% по сравнению с использованием async/await .

Заключение

Выбирать фреймворк следует исходя из характеристик проекта, который вы разрабатываете:

  • Если проект большой и требует интеграций сложных компонентов, стоит выбрать Django.
  • Для небольших проектов, обучения или приложений с веб-сокетами и NoSQL больше подойдут Flask и Tornado.

Никогда не останавливайтесь: В программировании говорят, что нужно постоянно учиться даже для того, чтобы просто находиться на месте. Развивайтесь с нами — на Хекслете есть сотни курсов по разработке на разных языках и технологиях

Что можно сделать на Tornado?

Я умею и могу в Pyramid и Flask. С некоторых пор захотелось изучить что-нибудь новое и я решил узнать про фреймворк Tornado.

Интересует вопрос: для каких задач лучше всего подойдёт именно он? Чаще всего вижу примеры задач, где с помощью Tornado пишут чат на веб-сокетах. но ведь этот фреймворк используется не только для написания чатов, правда? Правда же? Говорят, писать веб-приложения с использованием шаблонизаторов — то есть «обычные сайты» — на Торнадо расточительно: он может и умеет, но это лучше сделать на других фреймворках, которые лучше предназначены именно для этих целей, таких как Pyramid, Flask. Django etc. А есть ли задачи, глядя на которые тим-лид скажет, что вот тут лучше всего подойдёт именно Tornado?

Или, что ещё лучше, может быть у вас завалялись тестовые задачи при устройстве на работу, где пишут сервисы на Tornado и которые вам не жалко открыть? Буду благодарен за любые задания!

  • Вопрос задан более трёх лет назад
  • 23149 просмотров

Комментировать
Решения вопроса 3

bobrovskyserg

bobrovskyserg @bobrovskyserg
Посмотрите вот это, прежде чем хвататься за Торнадо.
Ответ написан более трёх лет назад
Нравится 8 3 комментария

Tark

Tark @Tark Автор вопроса

Спасибо! Похоже, пора плотно переходить на Python 3. Уж больно простым становится асинхронное программирование с aiohttp.

leahch

А еще на twisted гляньте, там и 2.7 еще в теме.

bobrovskyserg

bobrovskyserg @bobrovskyserg

Tark:
Поставьте ответ решением.
Средства языка здорово выросли, и надо продвигать их, а не ~censored~ антикварное (я про твистед).

mututunus

Backend developer (Python, Golang)

На tornado можно сделать все что угодно, вопрос в целесообразности. Но больше всего он подходит для задач с большим количеством http-запросов. Напишите например агрегатор ленты нескольких соц. сетей и/или rss.

Ответ написан более трёх лет назад
Нравится 4 2 комментария

Tark

Tark @Tark Автор вопроса

Что на Tornado можно сделать что угодно, это понятно. Более того, почти на всём можно сделать почти всё. Используется, если нужно обработать большое количество HTTP-запросов? Но если посмотреть на (довольно старое и крайне сомнительное) сравнение, то торнадо ничем особенным не выделяется. И «длительная обработка запроса (например, по причине взаимодействия с сервером баз данных), сводит преимущества Торнадо на нет» (с) википедия.

Тем не менее, в правой части этого сайта иногда пишут вакансии Python-программистов и там иногда требуется знание Tornado. Что же это? Неужели просто наследие? Или всё-таки есть какие-то задачи, где лучше всего подойдёт именно этот фреймворк?

Вопрос-то состоит в том, для чего Tornado был написан помимо «фатального недостатка». Это не значит, что мне нечем себя занять и я прошу дать мне какую-то задачу, чтобы я познакомился с этим фреймворком — уж с этим-то я и сам справлюсь 🙂

leahch

Это кто же сказал, что торнадо и «длительная обработка запроса» как-то связаны?! Просто их, запросы к базе, делайте асинхронно. Хотя на чистом торнадо может быть так и есть, я всё больше за cyclone (клон торнадо) + twisted.

leahch

Я мастер на все руки, я козлик Элек Мэк 🙂

Для чего я использую tornado, точнее cyclone.io, порт tornado под twisted.

— для системы miidleware ТВ-приставок. Приставка лезет за страничкой к серверу, а в остальное время общается с ним по json/REST/comet. Админка статистики этого дела работает на отдельном порту и содержит 10 страниц + json/comet/rest.
— для системы доступа к кластеру с тонких клиентов, сервер отдает данные в json о доступных точках входа на сервера кластера и запоминает выбор пользователя. Всего 30 строк кода, Карл 🙂 С одной стороны сервер подключается в influxdb, с другой отдает данные пользователям.
— для админок к разным устройствам
— для вещей, когда просто нужен вебсервер и шаблоны, и не нужна база данных, ORM, и куча лишнего говна.
— для вещей, когда web-интерфейс как небольшая часть остального функционала
— для web, когда нужно быстро туда-сюда прогнать данные.

Если посмотреть на отличия с django, то django умеют делать отличный фреймворк для web, а торнадо — отличный фреймворк для http!

А чего далеко ходить. Простая конфигурилка для линукса, интерфейсы, логин/пароль, просмотр и конфигурилка запущенных служб. Раньше я это делал на webmin, теперь cyclon + angularjs.

А вот.. вот делаю дизайн html для битрикс (уж простите. ). Как-то нужно смотреть html/css + картинки + javascript, причем, все с путями реального сайта — 10 минут и у меня всё готово. Ну не апач с nginx для этого разворачивать же?

Ну и как-то была задача типа чата (для удаленных устройств), когда нужно было обеспечить около 10к подключений. Без танцев с бубном и минимум кода.

В общем везде, где просто нужен быстрый и простой web-сервер с моторчиком из питона. Раньше я для этого использовал jetty (java) с моторчиком на яве соответственно. На питоне это проще в два/три раза только из-за того, что можно по ssh зайти и тупо поправить в коде без компиляции (maven) и среды разработки (eclipse).

Ответ написан более трёх лет назад
Нравится 3 6 комментариев

Tark

Tark @Tark Автор вопроса
Спасибо! А можно ещё парочку примеров насчёт «вещей, когда просто нужен вебсервер и шаблоны».

Tark

Tark @Tark Автор вопроса

Спасибо 🙂 Кажется, что вам просто нравится Tornado (исключая последний пример, когда действительно может пригодиться). Мне пришло в голову возможное применение торнадо для хранения и обработки состояний чего-нибудь типа игроков в онлайн-игре или, я не знаю, месторасположения таксистов и пассажиров для показа всего этого на сайте/приложении. Но стоит ли тогда целенаправленно изучать этот фреймворк или правда стоит перейти на третий питон и врубиться в asyncio/aiohttp?

leahch

leahch

Tark: О. Как раз для этого (хранение и обработка в играх) очень часто его пользуют. Ну и конечно мне нравится — 5 строк кода и у вас готовый сервер с батарейкой, + 10 строк кода и уже готовое приложение!

leahch

На счет того, нужен или нет торнадо, он простой как две копейки, за неделю освоите полностью. А на aiohttp я сейчас и сам гляну. Про торнадо уже сказал, быстрота и простота рулит у него.

leahch

Ну что, досмотрел про aiohttp, очень неплохо! Понравилось сравнение с торнадо, и что они не будут делать мегамонстра. Вообще очень, на первый взгляд, вкусно. буду пробовать. Комментарии порадовали.

Ответы на вопрос 4

Tark

Tark @Tark Автор вопроса
Pyramid’альный мир

Посмотрел на aiohttp, осталось странное такое впечатление.

Начнём с того, что асинхронный aiohttp в 2-5 раз медленнее синхронных топов на самой простой задаче — вернуть JSON. Окей, в реальной жизни засчёт однопоточности и ненужности кеш-серверов скорость сгладится.

Второе. Андрей Светлов говорил: «смотрите, у нас есть джынжа со с макой! Можно уже писать приложения!». Да.
aiohttp_jinja2 не проверяет в декораторе значение, которое ей передаётся. Вернули не словарь? Нате пятихатку!
Почему бы не проверять? Почему в шаблон не передаётся request по умолчанию, почему мне нужно будет вписывать его самостоятельно? Если бы мне хотелось многословия, я бы Django использовал.

Третье, про aiohttp.web. В pyramid, к примеру, есть чёткое разделение между роутом и вью-функцией, где роут — это URL с именем, а во вьюшке можно определить обработчик роута в зависимости от HTTP-метода и прочего. В результате можно строить URL в шаблоне, указывая имя роута и необходимые параметры; очень удобно. В отличие от pyramid, в aiohttp есть понятие роута, где сразу же указывается HTTP-метод, URL и обработчик. Что самое злое, метод тут — ТОЛЬКО СТРОКА. Не список/множество возможных методов типа method=(‘GET’, ‘POST’), а только строка. В результате необходимо придумывать разные name для роута для одного и того же URL, что добавляет неудобства для их построения. И чёртово отсутствие request в шаблоне, чёрт бы его подрал. Ну не хочу я вертать взад dict(request=request, user=’Tark’), я хочу без реквеста, но чтобы оно в шаблон передавалось самим aiohttp. Аргх!

Что понравилось — aioauth-client. Ужасное название пакета, но какая прелесть внтурях. Осталось чуток дописать, чтобы не приходилось делать if ‘twitter’ elif ‘github’ elif ‘google’, добавить роутов и можно получить нормально работающий python-social-auth-light.

Но пока что всё это слишком не доработанное. Разработка идёт гигантскими шагами, но результат пока ещё использовать тяжело.

Tornado — веб-фреймворк реального времени

Tornado

Tornado — версия расширяемого, неблокирующего веб-сервера с открытым исходным кодом и средств, на которых работает FriendFeed. Приложение FriendFeed написано с использованием веб-фреймворка, в некоторой степени похожего на web.py или Google’s webapp, но с дополнительными средствами и оптимизацией для получения преимуществ использования неблокирующей инфраструктуры.

Фреймворк Tornado отличается от большинства фреймворков веб-серверов (и, разумеется, большинства Python-фреимворков), так как он неблокирующий и достаточно быстрый. Tornado неблокирующий и использует epoll, он может обрабатывать тысячи одновременных постоянных подключений, что делает его идеальным решением для веб-сервисов реального времени. Этот веб-сервер специально разработан для обслуживания возможностей, требующих работы в реальном времени — каждый активный пользователь FriendFeed поддерживает открытое соединение с серверами FriendFeed. (Для получения более подробной информации по масштабированию серверов обратитесь к статье C10K problem.)

Вы можете ознакомиться с Документацией по Tornado для детального знакомства с фреймворком.

Данная статья предлагает краткое введение в Tornado.

Загрузка и установка Tornado

tar xvzf tornado-0.1.tar.gz cd tornado-0.1 python setup.py build sudo python setup.py install

Предпосылки

Tornado проверен на Python 2.5 и 2.6. Для использования всех возможностей Tornado, Вам потребуются установленные PycURL и библиотека JSON типа simplejson. Подробные инструкции по установке для Mac OS X и Ubuntu приведены ниже для Вашего удобства.

Mac OS X 10.5/10.6

sudo easy_install setuptools pycurl==7.16.2.1 simplejson
sudo apt-get install python-dev python-pycurl python-simplejson

Hello, world

Приведём традиционный пример приложения «Hello, world» для Tornado:

import tornado.httpserver import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") application = tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": http_server = tornado.httpserver.HTTPServer(application) http_server.listen(8888) tornado.ioloop.IOLoop.instance().start()

Обсуждение и поддержка

Вы можете обсудить Tornado и сообщить об ошибках в списке рассылки разработки Tornado.

Вся документация распространяется под лицензией Creative Commons 3.0.

Оригинал статьи Tornado, перевод КОМТЕТ komtet.ru

Вам также может помочь

Виртуальный хостинг Perl/PHP/Python/Ruby

Тарифные планы «Виртуальный хостинг» — от размещения статических HTML-страниц, до поддержки PHP, Python, CGI скриптов (Shell, Perl), SSI, Ruby. В рамках тарифных планов предоставляется доступ к серверам баз данных MySQL или PostgreSQL.

Документация к веб-серверу Tornado

Tornado — открытая версия масштабируемого, неблокирующего веб сервера, а также набор инструментов, которые используются сервисом FriendFeed. Приложение FriendFeed написано с использованием фреймворка, который выглядит как web.py или веб приложение Google, но имеет ряд дополнительных инструментов и оптимизаций, добавленых с целью получения всех выгод от низлежащей неблокирующей инфраструктуры.

  1. Документация к веб-серверу Tornado
  2. Обзор
  3. Загрузка
    1. Подготовка
    1. Основные модули
    2. Низкоуровневые модули
    3. Другие модули
    1. Обработчики и параметры запросов
    2. Шаблоны
    3. Cookies и защищенные cookies
    4. Аутентификация пользователей
    5. Защита от CSRF
    6. Статические файлы и агрессивное кеширование файлов
    7. Локализация
    8. Модули пользовательского интерфейса
    9. Неблокирующие, асинхронные запросы
    10. Аутентификация с помощью сторонних разработчиков

    Обзор

    Веб-сервер, который обслуживает сервис FriendFeed — относительно простой, неблокирующий веб сервер, написанный на языке Python.

    Tornado — открытая версия масштабируемого, неблокирующего веб сервера, а также набор инструментов, которые используются сервисом FriendFeed. Данный фреймворк отличается от большинства мейнстримовских (и, определенно, от большинства Python фреймворков), потому что использование неблокирующего принципа дает порядочное ускорение. Благодаря этому, а также благодаря использованию epoll, он может обрабатывать тысячи одновременных соединений, а это значит, что этот фреймворк идеален для создания веб сервисов реального времени. Мы построили веб сервер конкретно для того, чтобы обрабатывать функции сервиса FriendFeed в реальном времени: каждый активный пользователь поддерживает открытое соединение с серверами. (Для получения дополнительной информации о масштабировании серверов для поддержки тысяч клиентов, прочитайте о проблеме C10K.)

    Загрузка

    На GitHub Вы также можете просмореть исходный код, включающий в себя демонстрационные приложения. Чтобы установить Tornado:

     1  tar xvzf tornado-0.2.tar.gz  2  cd tornado-0.2  3  python setup.py build  4  sudo python setup.py install 

    После установки, вы получите возможность запустить любое из демонстрационных приложений из папки demos, которые включены в пакет Tornado.

     1  ./demos/helloworld/helloworld.py 

    Подготовка

    Tornado тестировался на Python 2.5 и 2.6. Для того, чтобы использовать все функции Tornado, вам нужны библиотеки PycURL и JSON, например simplejson. Полные инструкции по установке на Mac OS X и Ubuntu показаны ниже.

    Mac OS X 10.5/10.6

     1  sudo easy_install setuptools pycurl==7.16.2.1 simplejson 

    Ubuntu Linux

     1  sudo apt-get install python-dev python-pycurl python-simplejson 

    Список модулей

    Наиболее важный модуль — web. Он является фреймворком, включающим в себя большинство функций пакета Tornado. Другие модули — это инструменты, которые делают модуль web богаче. Смотрите Руководство по Tornado ниже для получения более полной информации о пакете web.

    Основные модули

    • web — веб фреймворк, на котором построен FriendFeed. web содержит большинство важных функций Tornado
    • escape — методы кодирования/декодирования XHTML, JSON и URL
    • database — Простая обертка вокруг MySQLdb для упрощения спользования СУБД MySQL
    • template — язык шаблонов, в основу которого положен синтаксис языка Python
    • httpclient — неблокирующий HTTP клиент для работы с модулями web и httpserver
    • auth — реализация схем аутентификации и авторизации от третих разработчиков (Google OpenID/OAuth, Facebook Platform, Yahoo BBAuth, FriendFeed OpenID/OAuth, Twitter OAuth)
    • locale — поддержка локализации/интернационализации
    • options — синтаксический анализатор файлов настроек и аргументов коммандной строки, оптимизированный для использования в среде сервера

    Низкоуровневые модули

    • httpserver — очень простой HTTP сервер, на основе которого построен модуль web
    • iostream — простая обертка вокруг неблокирующих сокетов для обеспечения общих шаблонов считывания и записи
    • ioloop — основная петля ввода/вывода

    Другие модули

    • s3server — веб сервер, который реализует большую часть интерфейса Amazon S3, с локальным файловым хранилищем данных

    Руководство

    Обработчики и параметры запросов

    Веб Приложение Tornado отображает (maps) URL или шаблоны URL в подклассы tornado.web.RequestHandler. Эти классы определяют get() и post() методы для обработки запросов HTTP GET и POST по заданному URL.

    Код, что приводится ниже, отображает корневой URL / в MainHandler, а шаблон URL /story/([0-9]+) в StoryHandler. Регулярные выражения передаются в качестве аргументов методам класса RequestHandler:

     1  class MainHandler(tornado.web.RequestHandler):  2  def get(self):  3  self.write("You requested the main page")  4    5  class StoryHandler(tornado.web.RequestHandler):  6  def get(self, story_id):  7  self.write("You requested the story " + story_id)  8    9  application = tornado.web.Application([  10  (r"/", MainHandler),  11  (r"/story/([0-9]+)", StoryHandler),  12  ]) 

    С помощью метода get_argument() вы можете получить аргументы строки запроса и распарсить тело POST запроса:

     1  class MainHandler(tornado.web.RequestHandler):  2  def get(self):  3  self.write('"/" method="post">'  4  '"text" name="message">'  5  '"submit" value="Submit">'  6  ' ')  7    8  def post(self):  9  self.set_header("Content-Type", "text/plain")  10  self.write("You wrote " + self.get_argument("message")) 

    Если вы хотите отправить сообщение об ошибке клиенту, например, 403 Unauthorized, вам достаточно вызвать исключение tornado.web.HTTPError:

     1  if not self.user_is_logged_in():  2  raise tornado.web.HTTPError(403) 
    • arguments — все аргументы GET и POST запроса
    • files — все загруженные файлы (через запросы multipart/form-data POST)
    • path — путь запроса (все, что находится в строке запроса перед ?)
    • headers — заголовки запроса

    Смотрите определение класса HTTPRequest в модуле httpserver для получения полного списка атрибутов.

    Шаблоны

    Вы можете использовать любой язык шаблонов, поддерживаемый языком Python, но Tornado имеет свой собственный, который намного быстрее и гибче, чем множество популярных систем шаблонов. Для получения полной информации обратитесь к документации по модулю template.

    Шаблон Tornado — простой HTML (или другой текстовый формат), содержащий вложенные управляющие последовательности, которые являются выражениями, заключенными в разметку:

     1  html>  2  head>  3  title>>title>  4  head>  5  body>  6  ul>  7   8  li>>li>  9   10  ul>  11  body>  12  html> 

    Если вы сохранили этот шаблон как «template.html», и положили в ту же папку, что и файл Python, отобразите этот шаблон следующим образом:

     1  class MainHandler(tornado.web.RequestHandler):  2  def get(self):  3  items = ["Item 1", "Item 2", "Item 3"]  4  self.render("template.html", title="My title", items=items) 

    Шаблоны Tornado поддерживают управляющие последовательности и выражения. Управляющие последовательности заключены в символы и %>, например, 2 %>. Выражения заключены в символы < < и >>, например, < < items[0] >>.

    Управляющие последовательности более менее точно соответствуют предложениям языка Python. Мы поддерживаем if, for, while, и try, каждое из которых заканчивается последовательностью символов . Мы также поддерживаем наследование шаблонов через предложения extends и block, которые более детально описаны в документации к модулю template.

    Выражения могут быть любыми, соответствующими языку Python, включая вызовы функций. Мы поддерживаем функции escape, url_escape, и json_encode по молчанию, но вы можете передать любые другие функции в шаблон через ключевые аргументы функции render модуля template:

     1  class MainHandler(tornado.web.RequestHandler):  2  def get(self):  3  self.render("template.html", add=self.add)  4    5  def add(self, x, y):  6  return x + y 

    Когда вы разрабатываете реальное приложение, возможно вы захотите использовать все функции шаблонов Tornado, особенно наследование. Почитайте о всех функциях шаблонов в документации к модулю template.

    Под капотом шаблоны Tornado транслируются прямо в Python. Выражения из шаблонов копируются без изменений в Python функцию, которая представляет шаблон. Мы не пытаемся предостеречь вас от каких либо действий в языке шаблонов; мы создали его для того, чтобы обеспечивать гибкость, которая не свойственна другим, более строгим языкам шаблонов. Следовательно, если вы напишите внутри выражений какую-нибудь несуразицу, то получите ошибки Python во время выполнения.

    Cookies и защищенные cookies

    cookies можно установить в обозревателе пользователя с помощью метода set_cookie:

     1  class MainHandler(tornado.web.RequestHandler):  2  def get(self):  3  if not self.get_cookie("mycookie"):  4  self.set_cookie("mycookie", "myvalue")  5  self.write("Your cookie was not set yet!")  6  else:  7  self.write("Your cookie was set!") 

    Часто бывает, что cookies очень просто подделываются зловредными клиентами. Если вам нужно установить cookies чтобы, например, сохранить идентификатор авторизованного пользователя, вам следует их подписать для предотвращения подделки. Tornado предоставляет такую возможность из коробки через использование методов set_secure_cookie и get_secure_cookie. Чтобы использовать эти методы, вы должны указать секретный ключ, который называется cookie_secret, когда создаете приложение. Для реализации этого вам нужно передать его в настройках приложения как ключевой аргумент:

     1  application = tornado.web.Application([  2  (r"/", MainHandler),  3  ], cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=") 

    Подписанные cookies содержат закодированное значение cookie плюс timestamp и подпись (сигнатуру) HMAC. Если cookie устарела, или подпись не совпадает, метод get_secure_cookie вернет None, как будто cookie не была установлена. Вот защищенная версия примера, приводимого выше:

     1  class MainHandler(tornado.web.RequestHandler):  2  def get(self):  3  if not self.get_secure_cookie("mycookie"):  4  self.set_secure_cookie("mycookie", "myvalue")  5  self.write("Your cookie was not set yet!")  6  else:  7  self.write("Your cookie was set!") 

    Аутентификация пользователей

    Проверка подлинности пользователя доступна в каждом обработчике запроса как self.current_user, и в каждом шаблоне как current_user. По умолчанию current_user имеет значение None.

    Для осуществления аутентификации в вашем приложении вам нужно переопределить метод get_current_user() в вашем обработчике запроса, чтобы определить текущего пользователя, например, значение куки. Ниже приведен пример, который позволяет пользователям войти в приложение просто указав ник, который потом сохраняется в куке:

     1  class BaseHandler(tornado.web.RequestHandler):  2  def get_current_user(self):  3  return self.get_secure_cookie("user")  4    5  class MainHandler(BaseHandler):  6  def get(self):  7  if not self.current_user:  8  self.redirect("/login")  9  return  10  name = tornado.escape.xhtml_escape(self.current_user)  11  self.write("Hello, " + name)  12    13  class LoginHandler(BaseHandler):  14  def get(self):  15  self.write('"/login" method="post">'  16  'Name: "text" name="name">'  17  '"submit" value="Sign in">'  18  ' ')  19    20  def post(self):  21  self.set_secure_cookie("user", self.get_argument("name"))  22  self.redirect("/")  23    24  application = tornado.web.Application([  25  (r"/", MainHandler),  26  (r"/login", LoginHandler),  27  ], cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=") 

    Вы можете потребовать, чтобы пользователь аутентифицировался в приложении используя декоратор tornado.web.authenticated. Если запрос передается методу с этим декоратором и пользователь не залогинен он будет перенаправлен на login_url (который вы указываете в настройках приложения). Перепишем пример выше с использованием этого декоратора:

     1  class MainHandler(BaseHandler):  2  @tornado.web.authenticated  3  def get(self):  4  name = tornado.escape.xhtml_escape(self.current_user)  5  self.write("Hello, " + name)  6    7  settings =  8  "cookie_secret": "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=",  9  "login_url": "/login",  10  >  11  application = tornado.web.Application([  12  (r"/", MainHandler),  13  (r"/login", LoginHandler),  14  ], **settings) 

    Если вы используете этот декоратор аутентификации для метода post() и пользователь не залогинен, то сервер пошлет в ответ ошибку 403.

    Tornado поставляется со встроенной поддержкой схем аутентификации сторонних производителей, например Google OAuth. Посмотрите документуацию по модулю auth для получения подробной информации, либо раздел документации посвященный аутентификации с помощью сторонних разработчиков.

    Также рекомендуем ознакомиться с демонстрационным приложением Blog, идущим в комплекте с Tornado, чтобы получить представление об устройстве приложения, использующего аутентификацию и сохраняющего пользовательские данные в БД MySQL

    Защита от CSRF

    Cross-site request forgery, или XSRF (CSRF) — обычная проблема персонализированных веб приложений. Суть этой уязвимости сводится к тому, что размещенная злоумышленником внешняя ссылка на сайт или форма, отправляя внешний GET или POST запрос может использовать активную аутентифицированную сессию пользователя на атакуемом сайте, чтобы отправить определенный запрос «от его имени». Смотрите статью в википедии для получения более полной информации о, как работает XSRF.

    Общепринятое решение для предотвращения XSRF — устанавливать cookie для каждого пользователя с непредсказуемым значением и включать это значение как дополнительный аргумент в каждую форму на вашем сайте. Если cookie и ее значение при отправке формы не совпадают, то запрос определяется как подделанный.

    Tornado содержит встроенную защиту от XSRF. Для ее активирования, включите опцию xsrf_cookies в настройках приложения:

     1  settings =  2  "cookie_secret": "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=",  3  "login_url": "/login",  4  "xsrf_cookies": True,  5  >  6  application = tornado.web.Application([  7  (r"/", MainHandler),  8  (r"/login", LoginHandler),  9  ], **settings) 

    Если xsrf_cookies установлена, веб приложение Tornado будет устанавливать _xsrf cookie для всех пользователей и отклонять все POST запросы, которые не содержать верного значения _xsrf. Если вы включите эту опцию, вы должны включить поле во все формы, которые отправляются на сервер посредством POST запроса. Сделать это можно специальной функцией xsrf_form_html(), которая доступна во всех шаблонах по умолчанию:

     1  form action="/login" method="post">  2  >  3  div>Username: input type="text" name="username"/>div>  4  div>Password: input type="password" name="password"/>div>  5  div>input type="submit" value="Sign in"/>div>  6  form> 

    Если вы отправляете AJAX POST запросы, вам также следует включить в JavaScript значение _xsrf при выполнении каждого запроса. Нже показана функция jQuery, которая используется в FriendFeed для AJAX POST запросов, автоматически добавляя значение _xsrf во все запросы:

     1  function getCookie(name)  2  var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");  3  return r ? r[1] : undefined;  4  >  5    6  jQuery.postJSON = function(url, args, callback)  7  args._xsrf = getCookie("_xsrf");  8  $.ajax(url: url, data: $.param(args), dataType: "text", type: "POST",  9  success: function(response)  10  callback(eval("(" + response + ")"));  11  >>);  12  >; 

    Статические файлы и агрессивное кеширование файлов

    Вы можете обслуживать статические файлы с помощью Tornado, через указание настройки static_path в вашем приложении.

     1  settings =  2  "static_path": os.path.join(os.path.dirname(__file__), "static"),  3  "cookie_secret": "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=",  4  "login_url": "/login",  5  "xsrf_cookies": True,  6  >  7  application = tornado.web.Application([  8  (r"/", MainHandler),  9  (r"/login", LoginHandler),  10  ], **settings) 

    Эта настройка автомтически сделает все запросы, которые начинаются со /static/ обслуживаемыми из директории для статичных файлов, например http://localhost:8888/static/foo.png использует foo.png из директории static_path. Также Tornado автоматически обслужвает файлы /robots.txt и /favicon.ico из директории статики (даже если перфикс /static/ не указан).

    В случае с браузерами, то неплохой идеей для увеличения производительности является агрессивное кэширование ресурсов, так чтобы не посылать ненужные запросы If-Modified-Since или Etag, ожидание обработки которых блокирует отображение страницы. Торнадо, будучи развернутым, сразу предоставляет такую возможность с помощью контроля версий статического контента.

    Чтобы использовать эту особенность нужно вызвать метод static_url() из вашего шаблона вместо того, чтобы вводить напрямую путь к статичному файлу в HTML:

     1  html>  2  head>  3  title>FriendFeed - >title>  4  head>  5  body>  6  div>img src="images/logo.png") >>"/>div>  7  body>  8  html> 

    Функция static_url() преобразует относительный путь в URI вроде /static/images/logo.png?v=aae54. Аргумент v — это хэш содержимого logo.png, и его наличие говорит Tornado отослать заголовки браузеру пользователя, что, в свою очередь, заставляет браузер кэшировать статичный файл на неопределенно долгове время.

    Так как аргумент v основан на содержимом файла, то если вы изменяете файл и перезапускаете сервер, начинает передаваться новое значение v и браузер пользователя загрузит новую версию файла. Если содержимое файла не изменилось, браузер продолжит использовать локальный кэш даже не проверяя изменения на сервере, что существенно увеличивает скорость отображения страницы.

    В производстве вы возможно захотите обслуживать статику более оптимизированным для этой цели сервером вроде nginx. Вы можете сконфигурировать почти любой web-сервер так, чтобы он поддерживал подобную семантику кэширования. Вот пример конфигурации nginx, который мы изпользуем в проекте FriendFeed

     1  location /static/  2  root /var/friendfeed/static;  3  if ($query_string)  4  expires max;  5  >  6  > 

    Локализация

    Локаль каждого пользователя (неважно вошел он в приложение он или нет) доступна всегда как атрибут self.locale обработчика запросов и как locale в шаблонах. Название локали (например, en_US) доступно через locale.name, а переводить строки вы можете методом locale.translate. Шаблоны также содержат глобальную функцию _(), с помощью которой также можно выполнять переводы строк. Функция translate имеет две формы:

     1  _("Translate this string") 

    которая переводит строку используя текущую локаль, и

     1  _("A person liked this", "%(num)d people liked this", len(people)) % "num": len(people)> 

    которая переводит строку, которая может быть единичной или множественной, основываясь на значении третьего аргумента. В примере выше перевод первой строки будет осуществлен, если len(people) равно 1, в противном случае будет выполнен перевод второй строки.

    Наиболее общий шаблон для переводов — использовать именованные заполнители (placeholders) Python для переменных, (например, как %(num)d в примере the example above).

    Вот правильно локализованный шаблон:

     1  html>  2  head>  3  title>FriendFeed - >title>  4  head>  5  body>  6  form action=">" method="post">  7  div>> input type="text" name="username"/>div>  8  div>> input type="password" name="password"/>div>  9  div>input type="submit" value="Sign in") >>"/>div>  10  >  11  form>  12  body>  13  html> 

    По умолчанию мы определяем пользовательскую локаль используя заголовок Accept-Language, который отсылается обозревателем. Если такого заголовка нет, то устанавливается локаль en_US. Если вы разрешите пользователям устанавливать свои предпочтения к локали, переопределите выборку локали по умолчанию, переопределив метод get_user_locale в обработчике запросов:

     1  class BaseHandler(tornado.web.RequestHandler):  2  def get_current_user(self):  3  user_id = self.get_secure_cookie("user")  4  if not user_id: return None  5  return self.backend.get_user_by_id(user_id)  6    7  def get_user_locale(self):  8  if "locale" not in self.current_user.prefs:  9  # Use the Accept-Language header  10  return None  11  return self.current_user.prefs["locale"] 

    Если get_user_locale возвращает None, мы обращаемся к заголовку запроса Accept-Language.

    Вы можете загрузить все переводы приложения используя метод tornado.locale.load_translations. Он берет из папки, которая должна содержать CSV файлы, файлы, которые названы за именем локали, например, es_GT.csv или fr_CA.csv. Метод загружает все переводы из этих CSV файлов и files and выводит список поддерживаемых локалей исходя из наличия CSV файлов. Обычно вы будете вызывать этот метод один раз в теле метода main() своего сервера:

     1  def main():  2  tornado.locale.load_translations(  3  os.path.join(os.path.dirname(__file__), "translations"))  4  start_server() 

    Вы можете получить список поддерживаемых локалей в приложении с помощью tornado.locale.get_supported_locales(). Пользовательская локаль выбирается из всех доступных так, чтобы как можно лучше подходить пользователю. Например, если локаль пользователя — es_GT, а локаль es поддерживается, то self.locale для этого запроса будет es. Если же подходящей локали не найдено, мы устанавливаем en_US.

    Посмотрите документацию к модулю locale для получения более полной информации о формате CSV и других методов локализации.

    Модули пользовательского интерфейса

    Для облегчения поддержки стандартных и многократно используемых виджетов вашими приложениями, в торнадо включена поддержка модулей пользовательского интерфейса (UI Modules). По сути, они являются особыми функциональными запросами на отображение компонентов вашей страницы и они идут в комплекте с собственными таблицами CSS и функциями JavaScript.

    Допустим, что у нас есть блог и мы хотим, чтобы записи этого блога присутствовали как на главной странице, так и на отдельных страницах записей. Для этого вы можете сделать класс Entry, унаследовав его от tornado.web.UIModule, вызывая который вы сможете отображать модуль записи на любой типе страницы. Для начала, создайте отдельный файл python в котором мы будем хранить модули интерфейса: uimodules.py и разместите в него следующий код:

     1  class Entry(tornado.web.UIModule):  2  def render(self, entry, show_comments=False):  3  return self.render_string(  4  "module-entry.html", show_comments=show_comments) 

    В настройках приложения укажите uimodules.py в качестве файла с модулями интерфейса, используя опцию ui_modules.

     1  class HomeHandler(tornado.web.RequestHandler):  2  def get(self):  3  entries = self.db.query("SELECT * FROM entries ORDER BY date DESC")  4  self.render("home.html", entries=entries)  5    6  class EntryHandler(tornado.web.RequestHandler):  7  def get(self, entry_id):  8  entry = self.db.get("SELECT * FROM entries WHERE >%s", entry_id)  9  if not entry: raise tornado.web.HTTPError(404)  10  self.render("entry.html", entry=entry)  11    12  settings =  13  "ui_modules": uimodules,  14  >  15  application = tornado.web.Application([  16  (r"/", HomeHandler),  17  (r"/entry/([0-9]+)", EntryHandler),  18  ], **settings) 

    В основном шаблоне home.html вы не включаете html-код напрямую, а ссылаетесь на модуль Entry

     1   2  >  3  

    В шаблоне отдельной записи entry.html вы также ссылаетесь на модуль Entry, но уже с аргументом show_comments , чтобы показать расширенный вариант модуля записи:

    В модули могут включаться произвольные CSS таблицы стилей и функции JavaScript посредством переопределеня методов embedded_css, embedded_javascript, javascript_files или css_files.

     1  class Entry(tornado.web.UIModule):  2  def embedded_css(self):  3  return ".entry "  4    5  def render(self, entry, show_comments=False):  6  return self.render_string(  7  "module-entry.html", show_comments=show_comments) 

    Модули CSS и JavaScript будут подключены к итоговой странице единократно, вне зависимости от количества вызовов модуля пользовательского интерфейса в пределах нее. CSS будет включена в элемент страницы, а JavaScript будет размещен прямо перед тегом в конце страницы.

    Неблокирующие, асинхронные запросы

    Обычно, когда заканчивается выполнение обработчика HTTP запроса, запрос автоматически завершается. Так как Tornado использует неблокирующий стиль ввода-вывода, но вы можете переназначить стандартное поведение, если хотите чтобы запрос оставался открытым после возврата из основного метода обработчика, используя декоратор класса-обработчика tornado.web.asynchronous.

    При его использовании вы должны сами вызвать self.finish(), чтобы завершить HTTP запрос, или вы создадите лишнюю нагрузку на браузер пользователя или «повесите» его.

     1  class MainHandler(tornado.web.RequestHandler):  2  @tornado.web.asynchronous  3  def get(self):  4  self.write("Hello, world")  5  self.finish() 

    Ниже приведен рабочий пример, который делает обращение к FriendFeed API, используя встроенный асинхронный HTTP клиент Торнадо:

     1  class MainHandler(tornado.web.RequestHandler):  2  @tornado.web.asynchronous  3  def get(self):  4  http = tornado.httpclient.AsyncHTTPClient()  5  http.fetch("http://friendfeed-api.com/v2/feed/bret",  6  callback=self.async_callback(self.on_response))  7    8  def on_response(self, response):  9  if response.error: raise tornado.web.HTTPError(500)  10  json = tornado.escape.json_decode(response.body)  11  self.write("Fetched " + str(len(json["entries"])) + " entries "  12  "from the FriendFeed API")  13  self.finish() 

    Когда метод get() возвращает управление, HTTP запрос остается незавершенным. Когда, наконец, вызывается метод on_responce(), запрос все еще открыт. В конце метода ответа мы должны отдать браузеру результат выполнения обработчика и закрыть соединение посредством вызова self.finish().

    Если вы вызываете асинхронные библиотечные функции, которые требуют ответа (например функция HTTP fetch в примере выше), вы должны обязательно обернуть их self.async_callback. Эта простая обертка гарантирует, что если ваша функция создаст исключение или программную ошибку, то браузеру будет послан соответствующий HTTP-ответ с кодом ошибки и соединение будет корректно завершено.

    В качестве более развернутого примера вы можете посмотреть приложение chat, идущее в качестве примера с Tornado, которое является чатом на основе AJAX и использует т.н. длинные запросы (long polling)

    Аутентификация с помощью сторонних разработчиков

    Модуль auth Tornado предоставляет протоколы авторизации и аутентификации для ряда наиболее популярных веб-сайтов, включая Google/Gmail, Facebook, Twitter, Yahoo и FriendFeed. Модуль включает методы авторизации пользователей через эти сайты и, где это возможно, методы доступа к сервисам, так что вы можете, например, загрузить пользовательские контакты или опубликовать сообщение в Твиттере, используя учетную запись пользователя.

    Вот пример обработчика, котрый использует Google для аутентификации, сохраняя полномочия в cookie для дальнейшего доступа:

     1  class GoogleHandler(tornado.web.RequestHandler, tornado.auth.GoogleMixin):  2  @tornado.web.asynchronous  3  def get(self):  4  if self.get_argument("openid.mode", None):  5  self.get_authenticated_user(self.async_callback(self._on_auth))  6  return  7  self.authenticate_redirect()  8    9  def _on_auth(self, user):  10  if not user:  11  self.authenticate_redirect()  12  return  13  # Save the user with, e.g., set_secure_cookie() 

    Обратите внимание, что обработчик использует декоратор асинхронного ввода-вывода, который осуществляет перенаправление на сайт google для аутентификации, сохраняя при этом открытый HTTP запрос.

    Более подробно вы можете узнать про это из документации к модулю auth.

    Производительность

    Производительность web-приложений в первую очередь ограничена архитектурой, а не производительностью frontend-а. И тем не менее Tornado весьма быстр по отношению к большинству популярных web-фреймворков на Python.

    Мы запустили несколько тестов на нагрузку, используя простое приложение типа «Hello, world!» на каждом из наиболее популярных Python web-фреймворков (Django, web.py и CherryPy) чтобы получить общее представление о производительности каждого из них по отношению к Tornado. Мы использовали Apache/mod_wsgi для Django и web.py, CherryPy был запущен на отдельном сервере, что соответствовало нашим представлениям о типичном окружении производственных решений каждого из фреймворков. Мы запустили 4 однопоточных Tornado фронтэнда за обратным прокси nginx, что соответствует нашим рекомендациям по запуску Tornado в производство. (наш тестовый сервер был четырехядерным и мы рекомендуем по одному фронтэнду на ядро).

    Тест каждого решения на нагрузку осуществлялся с помощью Apache Benchmark (ab) на отдельной машине с помощью команды

     1  ab -n 100000 -c 25 http://10.0.1.x/ 

    Результаты (обработанных запросов в секунду) на четырехядерном процессоре 2.4GHz AMD Opteron:

    По результатам наших тестов Tornado четырехкратно превосходил следующий по производительности фреймворк, и даже в однопоточном варианте (с использованием только одного ядра из четырех) оказался на 33% быстрее его.

    Методика не то чтобы научная, но в целом мы хотим донести до вас, что позаботились о производительности в процессе разработки Tornado, и он не создаст особых задержек в работе ваших приложений, характерных для большинства web-фреймворков на Python.

    Запуск Tornado на производстве

    В проекте FriendFeed мы используем nginx в качестве балансировщика нагрузки и сервера статики. У нас запущено множество экземпляров web-сервера Tornado на множестве серверов, обслуживающих фронтэнд. Обычно мы запускаем один фронтэнд Tornado на аппаратное ядро (иногда больше, в зависимости от ситуации).

    Это готовый конфигурационный файл nginx, который структурно схож с тем, что мы используем в проекте FriendFeed. В данном случае предполагается, что nginx и Tornado запущены на одной машине и четыре сервера Tornado запущены на портах с 8000 по 8003:

     1  user nginx;  2  worker_processes 1;  3    4  error_log /var/log/nginx/error.log;  5  pid /var/run/nginx.pid;  6    7  events  8  worker_connections 1024;  9  use epoll;  10  >  11    12  http  13  # Enumerate all the Tornado servers here  14  upstream frontends  15  server 127.0.0.1:8000;  16  server 127.0.0.1:8001;  17  server 127.0.0.1:8002;  18  server 127.0.0.1:8003;  19  >  20    21  include /etc/nginx/mime.types;  22  default_type application/octet-stream;  23    24  access_log /var/log/nginx/access.log;  25    26  keepalive_timeout 65;  27  proxy_read_timeout 200;  28  sendfile on;  29  tcp_nopush on;  30  tcp_nodelay on;  31  gzip on;  32  gzip_min_length 1000;  33  gzip_proxied any;  34  gzip_types text/plain text/html text/css text/xml  35  application/x-javascript application/xml  36  application/atom+xml text/javascript;  37    38  # Only retry if there was a communication error, not a timeout  39  # on the Tornado server (to avoid propagating "queries of death"  40  # to all frontends)  41  proxy_next_upstream error;  42    43  server  44  listen 80;  45    46  # Allow file uploads  47  client_max_body_size 50M;  48    49  location ^~ /static/  50  root /var/www;  51  if ($query_string)  52  expires max;  53  >  54  >  55  location = /favicon.ico  56  rewrite (.*) /static/favicon.ico;  57  >  58  location = /robots.txt  59  rewrite (.*) /static/robots.txt;  60  >  61    62  location /  63  proxy_pass_header Server;  64  proxy_set_header Host $http_host;  65  proxy_redirect false;  66  proxy_set_header X-Real-IP $remote_addr;  67  proxy_set_header X-Scheme $scheme;  68  proxy_pass http://frontends;  69  >  70  >  71  > 

    WSGI и Google AppEngine

    Торнадо поставляется с ограниченной поддержкой WSGI. Тем не менее, так как WSGI не поддерживает неблокирующие запросы вы не сможете использовать какие либо асинхронные/неблокирующие функции Tornado в вашем приложении, если вы предпочтете использовать WSGI вместо HTTP сервера Tornado. Некоторые возможности, недоступные для использования в WSGI приложениях: @tornado.web.asynchronous, httpclient и auth.

    Вы можете создать рабочее WSGI приложение с обработчиками запросов Tornado, используя WSGIApplication в модуле wsgi вместо tornado.web.Application. Далее приведен пример который использует встроенный WSGI CGIHandler для создания рабчего приложения Google AppEngine:

     1  import tornado.web  2  import tornado.wsgi  3  import wsgiref.handlers  4    5  class MainHandler(tornado.web.RequestHandler):  6  def get(self):  7  self.write("Hello, world")  8    9  if __name__ == "__main__":  10  application = tornado.wsgi.WSGIApplication([  11  (r"/", MainHandler),  12  ])  13  wsgiref.handlers.CGIHandler().run(application) 

    Посмотрите пример appengine для того, чтобы ознакомиться с полноценным приложением AppEngine, построенным на Tornado.

    Предостережения и поддержка

    Tornado является переработанным движком FriendFeed у которого были убранны специфичные для проекта зависимости. Рефакторинг мог породить ошибки. Так как серверы FriendFeed всегда работали за nginx, Tornado не был тщательно протестирован с клиентами HTTP/1.1 кроме Firefox. На данный момент Tornado не обрабатывает многострочные заголовки и некоторые варианты неправильно сформированных запросов.

    Вы можете обсудить Tornado и сообщить об ошибках в рассылке для разработчиков Tornado

    Перевод: Ростислав Дзинько, Илья Кутуков

    Документации/Tornado-web (последним исправлял пользователь RostislavDzinko 2010-07-26 17:37:55)

    • MoinMoin Powered
    • Python Powered
    • GPL licensed
    • Valid HTML 4.01

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *