Введение в Tornado / Хабр

Начни быстро

Процесс внедрения:

Проверочный код

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

Processes and ports¶

Due to the Python GIL (Global Interpreter Lock), it is necessary to run
multiple Python processes to take full advantage of multi-CPU machines.
Typically it is best to run one process per CPU.

Tornado includes a built-in multi-process mode to start several
processes at once (note that multi-process mode does not work on
Windows). This requires a slight alteration to the standard main
function:

This is the easiest way to start multiple processes and have them all
share the same port, although it has some limitations. First, each
child process will have its own IOLoop, so it is important that
nothing touches the global IOLoop instance (even indirectly) before the
fork.

For more sophisticated deployments, it is recommended to start the processes
independently, and have each one listen on a different port.
The “process groups” feature of supervisord
is one good way to arrange this. When each process uses a different port,
an external load balancer such as HAProxy or nginx is usually needed
to present a single address to outside visitors.

Static files and aggressive file caching¶

You can serve static files from Tornado by specifying the
static_path setting in your application:

settings={"static_path":os.path.join(os.path.dirname(__file__),"static"),"cookie_secret":"__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__","login_url":"/login","xsrf_cookies":True,}application=tornado.web.Application([(r"/",MainHandler),(r"/login",LoginHandler),(r"/(apple-touch-icon.png)",tornado.web.StaticFileHandler,dict(path=settings['static_path'])),],**settings)

Tornado web server — tornado 6.1 documentation

Tornado is a Python web framework and
asynchronous networking library, originally developed at FriendFeed. By using non-blocking network I/O, Tornado
can scale to tens of thousands of open connections, making it ideal for
long polling,
WebSockets, and other
applications that require a long-lived connection to each user.

Во-вторых, система маршрутизации

Система маршрутизации на самом деле является соответствующей взаимосвязью между URL-адресом и классом. Здесь отличается от других структур. Многие другие структуры являются соответствующими функциями URL-адреса. Каждый URL-адрес в Tornado соответствует классу.

PS: в кортеже маршрутизации первый параметр — это url, второй — класс, который нужно выполнить, третий — словарь, а четвертый параметр — имя: «».

Введение в Tornado / ХабрВведение в Tornado / Хабр
#!/usr/bin/env python
# -*- coding:utf-8 -*-import tornado.ioloop
import tornado.web
   
   
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
   
class StoryHandler(tornado.web.RequestHandler):
    def get(self, story_id):
        self.write("You requested the story "   story_id)
   
class BuyHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("buy.wupeiqi.com/index")
   
application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/story/([0-9] )", StoryHandler),
])
   
application.add_handlers('buy.wupeiqi.com$', [
    (r'/index',BuyHandler),
])
   
if__name__ == "__main__":
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()

Примеры систем маршрутизации

Tornado изначально поддерживает маршрутизацию доменных имен второго уровня, таких как:

В-третьих, шаблонизатор

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

Личное резюме обучения

Сводка обучения торнадо
 А. Вопрос: Что находится в веб-фреймворке?
	Django:
		 сокет: нет, wsgiref
		 Промежуточное ПО: Да
	   Система маршрутизации: Да
	   Функция просмотра: да
	    Операция ORM: Да
	   Шаблон движка: да
	 simple_tag: да
		 печенье: да
	    сессия: да
		   CSRF: да
		    xss: да
		   Другие: кеш, сигнал, форма, ModelForm, Admin
	  
	tornado:
		 сокет: да, wsgiref
	   Система маршрутизации: Да
	   Функция просмотра: да
	    Операция ORM: нет
	   Шаблон движка: да
	 simple_tag: Да, уиметод, уимодуль
		 печенье: да
	    сессия: нет
		   CSRF: да
		    xss: да
		    Другое: нет
	
	 Резюме: система маршрутизации, функция просмотра, шаблонизатор, cookie, csrf, xss
	
 б) установка торнадо
	pip3 install tornado 
	
 в) основное использование
		import tornado.ioloop
		import tornado.web
		from tornado.web import RequestHandler


		class IndexHandler(RequestHandler):
			def get(self):
				self.write("Hello, world")


		application = tornado.web.Application([
			(r"/index", IndexHandler),
		])

		if __name__ == "__main__":
			application.listen(8888)
			tornado.ioloop.IOLoop.instance().start()
			
	 Поддержка сопоставления по имени домена
	 В кортеже маршрутизации первый параметр - это url, второй - класс, который нужно выполнить, третий - словарь, а четвертый параметр - имя: ""

	 self.request инкапсулирует всю информацию запроса
	
 Также есть csrf_token

 В файле конфигурации:
	"xsrf_cookies": True,
 На языке шаблонов:
	 {{raw xsrf_form_html ()}} # Преобразовать метку типа строки в метку
	
 О печенье

 Простой текст:
	 self.set_cookie («имя», «значение, переданное в значении куки», expires = time.time ()   10 (время истечения)) # Установить куки
	 name = self.get_cookie ("name") # Получить куки

 Зашифрованный текст: написать на этикетку
	
	 В файле конфигурации: "cookie_secret": "asdf", # Настроить информацию о зашифрованных куки
	
	 Настроить:
	 self.set_secure_cookie ("nnn", пользователь, expires = time.time ()   10) # Установить помеченные куки
	 name = self.get_secure_cookie ("nnn") # Получить помеченные куки

 В файле конфигурации вы можете указать URL для перехода.
	
 Авторизация авторизации входа в систему Decorator Добавьте декоратор к функции, которая требует проверки входа в систему: 

	 @authenticated выполняет current_user самостоятельно, по сути, это функция, которая позволяет нам настраивать.
	 Просмотр исходного кода обнаружения ключевых функций
	if not hasattr(self, "_current_user"):
		self._current_user = self.get_current_user()
	return self._current_user
	 Чтобы определить, нет ли способа, выполните функцию get_current_user (), и в этой функции ничего не написано, поэтому мы можем использовать ее для настройки функции get_current_user, получения зашифрованных файлов cookie и возврата.
	
	 # Заявка
	from tornado.web import RequestHandler
	from tornado.web import authenticated

	 # Множественное наследование, получение куки, реализация аутентификации при входе в систему в виде декоратора
	class BaseRequestHandler(object):
		def get_current_user(self):
			return self.get_secure_cookie("nnn")

	 # Отметить порядок наследования
	class SeedHandler(BaseRequestHandler,RequestHandler):
		@authenticated
		def get(self, *args, **kwargs):
			seed_list = [
				 {"title": "Wheat", "price": 12},
				 {"title": "Ячмень", "цена": 14},
				 {"title": "Гречка", "цена": 16},
				 {"title": "Пшеничные отруби", "цена": 2},
			]
			self.render("seed.html",seed_list=seed_list)

 Пользовательский шаблон функции UIMethod для UIModule
	
	UIMethod
	 Создайте файл и напишите метод пользовательской функции
	 Существует параметр по умолчанию: self, который содержит все, что в данный момент называется классом
	
	 Если вы используете его, вам необходимо зарегистрироваться в файле конфигурации	
	 Страница {{function name ()}} выполняет вызов. Если это HTML-тег типа {% raw name ()%}, преобразуйте строку в тег
	
	
	UIModule
	 Метод вызова
	 {% имя класса модуля (передаваемое значение)%}
	
	 Возврат списка css в фоновом режиме и рендеринг в несколько тегов ссылок импортированных css файлов
	
	 CSS, который возвращает встроенный тип, должен добавить тег стиля в заголовочный файл страницы, а внутри находится атрибут, который мы написали.
	
	 Не только можете вернуть контент, но и настроить CSS и JS.

 На языке шаблонов:
	 Также поддерживает способ наследования материнской платы. Это точно так же, как метод в рамках Django.
	
 Торнадо рамки внутреннего процесса исполнения

	 Когда программа запускается, она выполняет методы в пользовательском классе (GET, POST ...). Когда класс определен, это должен быть метод __init__. Наконец, функция ловушки self.initialize (** kwargs) наконец выполняется в этой функции __init__
	
	Дело в том, что внутри этой функции не определен метод. Таким образом, мы можем переписать эту функцию [self.initialize (** kwargs)] в нашем собственном методе.
	
	 Прежде чем получить, опубликовать и другие функции, эта функция должна быть выполнена в первую очередь.
	
	 В системе маршрутизации третий параметр - это словарь, который используется для инициализации значения, а переданное местоположение - это функция self.initialize (** kwargs)

Рамки торнадо

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

import tornado.ioloop
import tornado.web
 из tornado.web import RequestHandler # обработка запросов

 # Маршрут, соответствующий методу обработки запроса (класс, унаследовавший метод Tornado requestthander)
class IndexHandler(RequestHandler):
         # Для получения запроса
    def get(self):

                 #Reverse генерирует URL в операции запроса
        # url1 = self.application.reverse_url('n1')
        # print(url1)
        # url2 = self.application.reverse_url('n2',666)
        # print(url2)

                 # Возврат содержимого страницы, эквивалентный HttpResponse в Django
        self.write("Hello, world")

                 # Возврат на страницу шаблона, эквивалентную визуализации в Django
                 # self.render ("*. htmltemplate path", "return value")

                 # Положение параметра возвращаемого значения - ** kwargs, поэтому вы можете написать словарь при передаче значения или написать каждый из параметров передачи k = v;
                 # Стоит отметить, что шаблон используется для визуализации результатов путем передачи ключа [{{key}}]. Если вам нужно передать параметры, будь то запрос GET или POST, вам необходимо соответствующим образом записать информацию о параметре
                 # GET return пуст, POST return является реальной информацией, иначе он сообщит об ошибке, потому что при рендеринге шаблона не может найти соответствующее значение ключа

                 Страница #Jump, эквивалентная перенаправлению в Django
                 # self.redirect ("адрес маршрутизации URL")

                 # О значении GET / POST
                 # self.get_query_argument ("key") # Получить параметр передачи определенного ключа
                 # self.get_query_arguments ("key") # Получить несколько параметров передачи определенного ключа
        #
                 # self.get_argument ("key") # Получите параметр передачи ключа из запросов get и POST, перейдите к двум запросам для поиска,
                 # self.get_arguments ("key") # Получить несколько параметров передачи ключа из запросов get и POST, перейдет к двум запросам для поиска

class HomeHandler(RequestHandler):
    def get(self,*args,**kwargs):
        import time

                 # Установите куки
                 # self.set_cookie ("имя", "значение, переданное в значении куки", expires = time.time ()   10 (время истечения)) #set куки
                 # name = self.get_cookie ("name") # Получить куки
                 # Получите зашифрованные куки
                 # self.set_secure_cookie ("name", "value set cookie value", expires = "timeout time") #set зашифрованные cookie
                 # self.get_secure_cookie ("name") # Получить зашифрованные куки

        self.write("Hello, world")

 # Файл конфигурации, тип словаря
settings = {
         "template_path": "Имя файла шаблона",
         "static_path": "Каталог статических файлов",
         "static_url_prefix": "Найти префикс статических файлов",
         "xsrf_cookies": True, #Enable csrf_token метод ссылки на страницу шаблона по умолчанию {% raw xsrf_form_html ()%}
         "cookie_secret": "asdf", # используется для настройки информации о зашифрованных куки
         'login_url': '/login.html', # начальный URL
         "ui_methods": "Имя функции импортированного файла функции пользовательского шаблона", # Пользовательская функция Тип функции
         "ui_modules": "Имя класса импортированного файла класса пользовательского шаблона", # Класс пользовательских функций
}
 # Создать веб-проект
application = tornado.web.Application([
         # Маршрутная система
    (r"/index", IndexHandler,{},"n1"),
    (r"/home/(d )", HomeHandler,{},'n2'),
 ], ** настройки) # Первый параметр проекта - система маршрутизации, второй - информация о конфигурации

 # Вы также можете добавить дополнительные маршруты. Когда вы посещаете, вы сначала будете искать здесь. Если вы этого не сделаете, вы найдете его на верхнем маршруте.
 application.add_handlers («URL доменного имени», [
         Маршрут #
])


 # Основное выполнение функции
if __name__ == "__main__":
         # Запуск проекта, мониторинг порта 8888
    application.listen(8888)
         #IO мультиплексирование начинает выполнение
    tornado.ioloop.IOLoop.instance().start()

 # Шаблонный метод цитирования статических файлов
 # 1, href = прямое обозначение маршрута
# 2, href = "{{static_url ('имя файла стиля')}}" При просмотре страницы вы обнаружите, что в файле после URL-адреса есть случайная строка (значение md5), которая генерируется md5 в фоновом режиме. Преимущества, предотвращают кеширование браузерами статических файлов

 # Язык шаблонов, как и Django, точно так же поддерживает наследование материнской платы.

Рамки торнадоОсновные учебные примеры

Очертание

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

Tornado явно отличается от текущих основных сред веб-серверов (включая большинство сред Python): это неблокирующий сервер, и он довольно быстрый. Воспользуйтесь его неблокирующим способом и правомepollС помощью приложения Tornado может обрабатывать тысячи соединений в секунду, что означает, что Tornado является идеальной веб-средой для веб-служб реального времени.

Основной целью нашей разработки этого веб-сервера является работа с функцией FriendFeed в режиме реального времени — каждый активный пользователь в приложении FriendFeed будет поддерживать соединение с сервером. (Чтобы узнать, как расширить сервер для обработки подключения тысяч клиентов, обратитесь кC10K problem。)

Пять, печенье

Tornado может работать с файлами cookie, а также подписывать файлы cookie для предотвращения подделки.

1. Основные операции

2. Зашифрованное печенье (подпись)

Файлы cookie легко подделываются вредоносными клиентами. Добавьте информацию о том, что вы хотите сохранить идентификатор пользователя, вошедшего в систему, в файл cookie. Вам необходимо подписать файл cookie, чтобы предотвратить подделку. Торнадо напрямую поддерживает эту функцию с помощью методов set_secure_cookie и get_secure_cookie.

Введение в Tornado / ХабрВведение в Tornado / Хабр
def _create_signature_v1(secret, *parts):
    hash = hmac.new(utf8(secret), digestmod=hashlib.sha1)
    for part in parts:
        hash.update(utf8(part))
    return utf8(hash.hexdigest())

#  шифрованиеdef _create_signature_v2(secret, s):
    hash = hmac.new(utf8(secret), digestmod=hashlib.sha256)
    hash.update(utf8(s))
    return utf8(hash.hexdigest())

def create_signed_value(secret, name, value, version=None, clock=None,
                        key_version=None):
    if version is None:
        version = DEFAULT_SIGNED_VALUE_VERSION
    if clock is None:
        clock = time.time

    timestamp = utf8(str(int(clock())))
    value = base64.b64encode(utf8(value))
    if version == 1:
        signature = _create_signature_v1(secret, name, value, timestamp)
        value = b"|".join([value, timestamp, signature])
        return value
    elif version == 2:
        # The v2 format consists of a version number and a series of# length-prefixed fields "%d:%s", the last of which is a# signature, all separated by pipes.  All numbers are in# decimal format with no leading zeros.  The signature is an# HMAC-SHA256 of the whole string up to that point, including# the final pipe.#
# The fields are:# - format version (i.e. 2; no length prefix)# - key version (integer, default is 0)# - timestamp (integer seconds since epoch)# - name (not encoded; assumed to be ~alphanumeric)# - value (base64-encoded)# - signature (hex-encoded; no length prefix)def format_field(s):
            return utf8("%d:" % len(s))   utf8(s)
        to_sign = b"|".join([
            b"2",
            format_field(str(key_version or 0)),
            format_field(timestamp),
            format_field(name),
            format_field(value),
            b''])

        if isinstance(secret, dict):
            assert key_version isnot None, 'Key version must be set when sign key dict is used'assert version >= 2, 'Version must be at least 2 for key version support'
            secret = secret[key_version]

        signature = _create_signature_v2(secret, to_sign)
        return to_sign   signature
    else:
        raise ValueError("Unsupported version %d" % version)

#  Дешифрированиеdef _decode_signed_value_v1(secret, name, value, max_age_days, clock):
    parts = utf8(value).split(b"|")
    if len(parts) != 3:
        return None
    signature = _create_signature_v1(secret, name, parts[0], parts[1])
    ifnot _time_independent_equals(parts[2], signature):
        gen_log.warning("Invalid cookie signature %r", value)
        return None
    timestamp = int(parts[1])
    if timestamp < clock() - max_age_days * 86400:
        gen_log.warning("Expired cookie %r", value)
        return None
    if timestamp > clock()   31 * 86400:
        # _cookie_signature does not hash a delimiter between the# parts of the cookie, so an attacker could transfer trailing# digits from the payload to the timestamp without altering the# signature.  For backwards compatibility, sanity-check timestamp# here instead of modifying _cookie_signature.
        gen_log.warning("Cookie timestamp in future; possible tampering %r",
                        value)
        return None
    if parts[1].startswith(b"0"):
        gen_log.warning("Tampered cookie %r", value)
        return None
    try:
        return base64.b64decode(parts[0])
    except Exception:
        return None


def _decode_fields_v2(value):
    def _consume_field(s):
        length, _, rest = s.partition(b':')
        n = int(length)
        field_value = rest[:n]
        # In python 3, indexing bytes returns small integers; we must# use a slice to get a byte string as in python 2.if rest[n:n   1] != b'|':
            raise ValueError("malformed v2 signed value field")
        rest = rest[n   1:]
        return field_value, rest

    rest = value[2:]  # remove version number
    key_version, rest = _consume_field(rest)
    timestamp, rest = _consume_field(rest)
    name_field, rest = _consume_field(rest)
    value_field, passed_sig = _consume_field(rest)
    return int(key_version), timestamp, name_field, value_field, passed_sig


def _decode_signed_value_v2(secret, name, value, max_age_days, clock):
    try:
        key_version, timestamp, name_field, value_field, passed_sig = _decode_fields_v2(value)
    except ValueError:
        return None
    signed_string = value[:-len(passed_sig)]

    if isinstance(secret, dict):
        try:
            secret = secret[key_version]
        except KeyError:
            return None

    expected_sig = _create_signature_v2(secret, signed_string)
    ifnot _time_independent_equals(passed_sig, expected_sig):
        return None
    if name_field != utf8(name):
        return None
    timestamp = int(timestamp)
    if timestamp < clock() - max_age_days * 86400:
        # The signature has expired.return None
    try:
        return base64.b64decode(value_field)
    except Exception:
        return None


def get_signature_key_version(value):
    value = utf8(value)
    version = _get_version(value)
    if version < 2:
        return None
    try:
        key_version, _, _, _, _ = _decode_fields_v2(value)
    except ValueError:
        return None

    return key_version

Внутренний алгоритм

Суть подписанного файла cookie заключается в следующем:

Примечание. Многие механизмы проверки API совпадают с механизмами реализации cookie-файлов безопасности.

Введение в Tornado / ХабрВведение в Tornado / Хабр
#!/usr/bin/env python
# -*- coding:utf-8 -*-import tornado.ioloop
import tornado.web
 
 
class MainHandler(tornado.web.RequestHandler):
 
    def get(self):
        login_user = self.get_secure_cookie("login_user", None)
        if login_user:
            self.write(login_user)
        else:
            self.redirect('/login')
 
 
class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        self.current_user()
 
        self.render('login.html', **{'status': ''})
 
    def post(self, *args, **kwargs):
 
        username = self.get_argument('name')
        password = self.get_argument('pwd')
        if username == 'aaa'and password == '123':
            self.set_secure_cookie('login_user', 'aaa')
            self.redirect('/')
        else:
            self.render('login.html', **{'status': 'Неверное имя пользователя или пароль'})
 
settings = {
    'template_path': 'template',
    'static_path': 'static',
    'static_url_prefix': '/static/',
    'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh'
}
 
application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/login", LoginHandler),
], **settings)
 
 
if__name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

Аутентификация пользователя на основе куки-демо

Введение в Tornado / ХабрВведение в Tornado / Хабр

#!/usr/bin/env python
# -*- coding:utf-8 -*-import tornado.ioloop
import tornado.web
 
class BaseHandler(tornado.web.RequestHandler):
 
    def get_current_user(self):
        return self.get_secure_cookie("login_user")
 
class MainHandler(BaseHandler):
 
    @tornado.web.authenticated
    def get(self):
        login_user = self.current_user
        self.write(login_user)
 
 
 
class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        self.current_user()
 
        self.render('login.html', **{'status': ''})
 
    def post(self, *args, **kwargs):
 
        username = self.get_argument('name')
        password = self.get_argument('pwd')
        if username == 'aaa'and password == '123':
            self.set_secure_cookie('login_user', 'aaa')
            self.redirect('/')
        else:
            self.render('login.html', **{'status': 'Неверное имя пользователя или пароль'})
 
settings = {
    'template_path': 'template',
    'static_path': 'static',
    'static_url_prefix': '/static/',
    'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh', #  Подписать куки'login_url': '/login'
}
 
application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/login", LoginHandler),
], **settings)
 
 
if__name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

Аутентификация пользователя на основе подписанных куки-демо

3. JavaScript операции куки

Файлы cookie хранятся в браузере, поэтому браузер также может использовать JavaScript для управления файлами cookie.

Для параметров:

Семь, загружай файлы

1. Форма загрузки

2. AJAX загрузка

Структура приложения

Мы не будем делать что-то более сложное чем «хелловорлд», но ключевые моменты я постараюсь передать. Каждое приложение на Торнадо, как правило, состоит из, собственно, класса приложения и классов хэндлеров (обработчиков) запросов. Класс простого приложения содержит в себе привязку хэндлеров к путям приложения и ряд настроек.

Так как приложение на Торнадо, это, по сути, сервер, он может запускаться с разнообразными параметрами, определёнными разработчиками. Для упрощения их получения используется модуль Торнадо options.

Класс приложения наследуется от класса tornado.web.Application. Он может выглядеть например так:

class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r«/», RootHandler),
]
settings = dict(
template_path=os.path.join(os.path.dirname(__file__)«templates»),
static_path=os.path.join(os.path.dirname(__file__)«static»),
xsrf_cookies=True,
cookie_secret=«11oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=»,
)
tornado.web.Application.__init__(self, handlers, **settings)
# MongoDB
self.connection = pymongo.Connection(MONGODB_HOST, MONGODB_PORT)
self.db = self.connection[«tornado»]

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

xsrf_cookies

включает генерацию токенов для форм для защиты XSRF.

cookie_secret

, как несложно догадаться, строка, используемая для генерации cookies. Здесь мы покачто не воспользуемся этим функционалом, но в дальнейших постах я опишу эти вещи. Следующая после настроек строка инициализирует класс приложения с обозначенными выше параметрами. Дальше я объявил подключение к базе данных MongoDB, чуть ниже мы передадим его в хендлеры.

Установка


Получить исходный код Торнадо можно из

на GitHub. Распаковываем архив и делаем:

python setup.py build
sudo python setup.py install

Торнадо так же можно поставить через easy_install:

sudo easy_install tornado

При этом важно чтобы были установлены пакеты

python-devpython-pycurlpython-simplejson

. Будем считать что с установкой вы справились и продолжим дальше.

Хендлеры


Хендлеры это классы, обрабатывающие входящие запросы в соответствии с правилами роутинга для приложения. Думаю, вы знаете что такое роутинг, так что объяснять не буду. В общем виде класс хендлера выглядит вот так:

class RootHandler(tornado.web.RequestHandler):
def get(self):
# do something here
self.write(«Hello, world»)

Этот класс будет обрабатывать GET запросы, пришедшие на корневой адрес, то есть на

. В данном случае мы просто возвращаем строку «Hello, world!». А вот так может выглядеть наследование хэндлеров:

class BaseHandler(tornado.web.RequestHandler):
@property
def db(self):
return self.application.db
class RootHandler(BaseHandler):
def get(self):
result = list(self.db.contents.find({}, limit=1))[0][«_id»]
self.write(str(result))

Мы объявляем класс базового хэндлера и проксируем в нём инициализированное выше подключение к базе данных. Затем объявляем корневой контроллер, наследуемый от базового и выводим по запросу Id первой записи в коллекции. Вы же слышали о MongoDB, правда?

Теперь осталось написать функцию main, которая получит управление после запуска сервера и инициализирует его.

Четыре, статические файлы

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

Примечание: реализация статического файлового кэша

Шесть, csrf

Подделка межсайтовых запросов в Торнадо аналогична таковой в Джанго,Подделка межсайтовых запросов

Примечание: при использовании Ajax важно получать локальные куки, переносить куки и отправлять запросы.

Оцените статью
Хостинги