Маршрутизация

Хотя потребители являются допустимыми приложениями ASGI, вы не хотите просто написать одно из них и сделать это единственным, что вы можете передать серверам протоколов, таким как Daphne. Channels предоставляет классы маршрутизации, которые позволяют вам объединять и складывать ваши потребители (и любые другие допустимые ASGI-приложения) для диспетчеризации на основе того, что является соединением.

Важно

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

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

Channels ожидает, что вы сможете определить одно корневое приложение и указать путь к нему в качестве параметра ASGI_APPLICATION (считайте, что это аналогично параметру << 1 >>> в Django). Не существует фиксированного правила относительно того, где нужно размещать маршрутизацию и корневое приложение, но мы рекомендуем следовать соглашениям Django и размещать их в файле уровня проекта под названием ROOT_URLCONF, рядом с asgi.py. Подробнее о развертывании проектов и настроек Channels вы можете прочитать в urls.py.

Вот пример того, как может выглядеть asgi.py:

import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.conf.urls import url
from django.core.asgi import get_asgi_application

from chat.consumers import AdminChatConsumer, PublicChatConsumer

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

application = ProtocolTypeRouter({
    # Django's ASGI application to handle traditional HTTP requests
    "http": get_asgi_application()

    # WebSocket chat handler
    "websocket": AuthMiddlewareStack(
        URLRouter([
            url(r"^chat/admin/$", AdminChatConsumer.as_asgi()),
            url(r"^chat/$", PublicChatConsumer.as_asgi()),
        ])
    ),
})

Примечание

Мы вызываем метод класса as_asgi() при маршрутизации наших потребителей. Он возвращает приложение-обертку ASGI, которое будет создавать новый экземпляр потребителя для каждого соединения или области видимости. Это похоже на метод Django as_view(), который играет ту же роль для экземпляров представлений, основанных на классах, для каждого запроса.

Можно также иметь маршрутизаторы из сторонних приложений или написать свои собственные, но мы рассмотрим здесь встроенные Channels.

ProtocolTypeRouter

channels.routing.ProtocolTypeRouter

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

Он позволяет вам отправлять на одно из нескольких других ASGI-приложений, основываясь на значении type, присутствующем в scope. Протоколы определяют фиксированное значение типа, которое содержит их область видимости, поэтому вы можете использовать его для различения типов входящих соединений.

Он принимает единственный аргумент - словарь, отображающий имена типов на приложения ASGI, которые их обслуживают:

ProtocolTypeRouter({
    "http": some_app,
    "websocket": some_other_app,
})

Если вы хотите разделить обработку HTTP между обработчиками long-poll и представлениями Django, используйте URLRouter, используя Django’s get_asgi_application(), указанный как последняя запись с шаблоном match-everything.

URLRouter

channels.routing.URLRouter

Маршрутизирует соединения типа http или websocket по их HTTP-пути. Принимает единственный аргумент - список объектов Django URL (либо path(), либо << 3 >>>):

URLRouter([
    re_path(r"^longpoll/$", LongPollConsumer.as_asgi()),
    re_path(r"^notifications/(?P<stream>\w+)/$", LongPollConsumer.as_asgi()),
    re_path(r"", get_asgi_application()),
])

Любые захваченные группы будут предоставлены в scope как ключ url_route, дикт с ключом kwargs, содержащим дикт именованных regex групп и ключ args со списком позиционных regex групп. Обратите внимание, что именованные и неименованные группы нельзя смешивать: Позиционные группы отбрасываются, как только совпадает одна именованная группа.

Например, чтобы вытащить именованную группу stream в примере выше, нужно сделать следующее:

stream = self.scope["url_route"]["kwargs"]["stream"]

Обратите внимание, что вложенность URLRouter не будет правильно работать с маршрутами path(), если внутренние маршрутизаторы обернуты дополнительным промежуточным программным обеспечением. См. Issue #1428.

ChannelNameRouter

channels.routing.ChannelNameRouter

Маршрутизирует диапазоны типа channel на основе значения ключа channel в их диапазоне. Предназначен для использования с ключом Рабочие и фоновые задачи.

Он принимает единственный аргумент - словарь, отображающий имена каналов на обслуживающие их ASGI-приложения:

ChannelNameRouter({
    "thumbnails-generate": some_app,
    "thumbnails-delete": some_other_app,
})
Вернуться на верх