- PVSM.RU - https://www.pvsm.ru -
Примечение переводчика: вебсокеты и Django — это довольно сложная тема, которая уже не раз поднималась на хабрахабре и основной идеей является написание параллельного бэкенда для вебсокетов. Автор же предлагает довольно лаконичное решение этой проблемы, которому правда еще предстоит проверка временем.
TL;DR — Я пришел к очень простому решению для работы с вебсокетами в Django. Все что вам нужно — это установить django-websocket-request [1], запустить скрипт, и теперь ваше приложение поддерживает вебсокеты! Это решение заставляет Django думать, будто он получает нормальный (в какой-то мере) HTTP-запрос, поэтому оно будет совместимо почти со всем вашим существующим кодом. Решение работает нормально как с Django Rest Framework [2], так и с обычными функциями-представлениями и представлениями, основанными на классах (Class Based Views).
Мы разрабатываем Blimp 2 [3] — это говорит о том, что у нас постоянно множество изменений в коде и инфраструктуре, и о том, как мы решаем старые и новые проблемы. Одно из решений, которое мы сделали в отношении нашего приложения, существенно изменило взаимодействие фронтенда и бэкенда.
В данный момент Blimp работает на Django. Он обслуживает наш HTML-код, обрабатывает наше публичное и приватное API, всю бизнес-логику. До последнего времени большинство веб-приложений примерно так и строились, однако Blimp имеет толстый JavaScript-клиент. С обычными запросами все происходит примерно следующим образом: вы запрашиваете URL, происходит какая-то работа со стороны бэкенда — запросы к базе данных, кеширование, обработка данных, отрисовка HTML-страниц, подгрузка сторонних CSS и JavaScript-библиотек, загрузка нашего собственного JavaScript-приложения, еще немного обработки данных, и наконец отрисовка результата.
Через несколько месяцев практики и роста нашего проекта, мы обнаружили несколько ключевых улучшений, которые мы можем внедрить — новая версия бэкенда должна будет заниматься формированием JSON, но не отрисовкой HTML, а наше фронтенд-приложение, которое выполняется со стороны клиента, будет просто потреблять данные через API. Мы решили, что оно будет использовать вебсокеты там, где это возможно, и обычный XHR во всех остальных случаях.
Веб-фреймворк Django и ему подобные построены для работы с циклом HTTP-запрос/ответ, поэтому всё в них, и представления, и механизмы аутентификации принимают HTTP-запрос на входе и отдают HTTP-ответ на выходе. С другой стороны, сервер вебсокетов не знает ничего о таком цикле.
Нашими главными целями были:
1. Одни и те же механизмы сериализации и десериализации данных, как со стороны HTTP-бэкенда, так и со стороны API вебсокетов.
2. Одна и та же бизнес-логика для всех.
Первой мыслью, которая пришла в голову, было превращение всей бизнес логики в методы наших моделей. Таким образом мы могли бы написать код единожды и разделить его между двумя бэкендами. В тот момент это казалось правильным решением, но через несколько часов было доказано, что нет. Так как мы работаем поверх Django REST framework, мы были бы вынуждены унаследовать и доработать десятки его классов и примесей, что на самом деле звучало не так уж плохо, но мы были настроены достаточно скептически и решили поискать другие идеи.
Мы знали, что хотим единое REST API, которое бы работало по двум каналам: HTTP и вебсокеты. Самым лучшим вариантом стало бы избежание переписывания чего бы то ни было только для работы его с вебсокетами. В какой-то момент меня озарило. Я вспомнил о Sails.js [4], который делает нечто подобное с тем, чего мы хотим достичь.
Sails поддерживает непривязанный к конкретному механизму обмен данными, что позволит вашим обработчикам автоматически работать и с Socket.io, и с вебсокетами. В прошлом вам пришлось бы писать отдельный код, чтобы получить такой результат.
Говоря более простым языком, мы хотели внедрить непривязанный ни к чему конкретному механизм обмена данными, который бы позволил нам использовать все что есть из Django-цикла запрос/ответ, чтобы автоматически формировать вебсокет-сообщения.
WebSocketRequest оказался неожиданно простым решением. Это простой класс, который принимает JSON-строку, содержащую следующие ключи: method, url, data, и token. Ключ method может быть любым HTTP-методом: GET, POST, PUT, DELETE, PATCH, HEAD или OPTIONS. Ключ url является абсолютным URL без доменного имени. Ключ data — это необязательный параметр — словарь, содержащий данные. Ключ token также является необязательным — используется для воссоздания заголовка HTTP-авторизации, авторизации через JSON Web Token или для ваших собственных ключей. Вы можете посмотреть мою статью [5], чтобы узнать больше о JSON Web Token, а если вы пользуетесь Django REST framework, то вам наверное понравится django-rest-framework-jwt [6].
WebSocketRequest работает следующим образом:
Да-да, фабрика запросов, вы прочитали верно. Вы можете быть знакомы с ней, если когда-нибудь писали тесты для Django-приложений, но если нет, фабрика запросов занимается тем, что генерирует объект запроса, который может быть использован как аргумент для любого представления. Единственным минусом является то, что такой запрос не поддерживает механизм middleware [8], что для некоторых может стать проблемой.
Мне определенно хотелось бы услышать о возможных проблемах данного подхода. В чем он может быть улучшен? Что может сломаться? Что насчет промышленного использования?
Обратите внимание, что Django в этом примере не используется вообще. Tornado [9] выдает статический HTML-файл и передает все вебсокет-запросы django-websocket-request, в котором уже и происходит вся магия.
Я установил демо-приложение на Heroku: http://dwr-example.herokuapp.com/ [10]. Будьте внимательны, данные периодически стираются. Если вы обнаружите какую-то ошибку, напишите мне в твиттере [11] о ней.
Вы можете установить WebSocketRequest при помощи pip:
pip install django-websocket-request
Исходный код:
https://github.com/GetBlimp/django-websocket-request [1]
Демо-приложение:
https://github.com/GetBlimp/django-websocket-request-example [12]
Автор: batment
Источник [13]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/news/54065
Ссылки в тексте:
[1] django-websocket-request: https://github.com/GetBlimp/django-websocket-request
[2] Django Rest Framework: http://www.django-rest-framework.org/
[3] Blimp 2: http://blog.getblimp.com/category/odp/
[4] Sails.js: http://sailsjs.org/
[5] статью : http://jpadilla.com/post/73791304724/auth-with-json-web-tokens
[6] django-rest-framework-jwt: https://github.com/GetBlimp/django-rest-framework-jwt
[7] фабрики запросов : https://docs.djangoproject.com/en/dev/topics/testing/advanced/#the-request-factory
[8] middleware: https://docs.djangoproject.com/en/dev/topics/http/middleware/
[9] Tornado: http://www.tornadoweb.org
[10] http://dwr-example.herokuapp.com/: http://dwr-example.herokuapp.com/
[11] твиттере: https://twitter.com/jpadilla_
[12] https://github.com/GetBlimp/django-websocket-request-example: https://github.com/GetBlimp/django-websocket-request-example
[13] Источник: http://habrahabr.ru/post/211094/
Нажмите здесь для печати.