如何使用Django Channels使用多个websocket连接?

Sco*_*les 2 django websocket django-channels

我已经很开心地使用Django-Channels已有几个月了。但是,我去了第二个依赖websocket的应用程序到我的Django项目中,我遇到了麻烦。

我得到的错误是websocket connection failed websocket is closed before the connection is established。奇怪的是,第一个应用程序在部署第二个应用程序之前就已运行。此外,只要第二个应用程序没有运行,第一个应用程序就可以继续工作。

Django的通道文档说:

Channels routers only work on the scope level, not on the level of individual events, which means you can only have one consumer for any given connection. Routing is to work out what single consumer to give a connection, not how to spread events from one connection across multiple consumers.

我认为这意味着Django-Channels不支持多个WebSocket连接的路由。也就是说,我想为两个不同的应用程序使用相同的websocket连接/端口。我的routing.py文件如下所示:

application = ProtocolTypeRouter({
    "websocket": AuthMiddlewareStack(
        URLRouter([
            path("first_application/stream/", app_1_consumers.AsyncApp1),
            path("second_application/stream/", app_2_consumers.AsyncApp2),
        ])
    )
})
Run Code Online (Sandbox Code Playgroud)

当我尝试使用下面的设置时,它找不到第一个应用程序的路径:

application = ProtocolTypeRouter({
    "websocket": AuthMiddlewareStack(
        URLRouter([
            path("second_application/stream/", app_2_consumers.AsyncApp2),
        ])
    ),
    "websocket02": AuthMiddlewareStack(
        URLRouter([
            path("first_application/stream/", app_1_consumers.AsyncApp1),
        ])
    ),

})
Run Code Online (Sandbox Code Playgroud)

如何设置Django应用程序以使用Django通道提供两个不同的Websocket连接?可能吗?还是我只是配置不正确?

Bri*_*ian 7

我在寻找类似的解决方案时遇到了这个 SO。如果我理解到目前为止我看到的解决方案,它们都需要在 Django 项目routing文件中指定消费者,如上面的答案(/sf/answers/3674811451/)中提到的:

application = ProtocolTypeRouter({

    # WebSocket chat handler
    "websocket": AuthMiddlewareStack(
        URLRouter([
            url(r"^chat/admin/$", AdminChatConsumer),
            url(r"^chat/$", PublicChatConsumer),
        ])
    ),
})
Run Code Online (Sandbox Code Playgroud)

如果您想在保持与教程类似的结构的同时扩展教程,可以执行以下操作:

application = ProtocolTypeRouter({
    # (http->django views is added by default)
    'websocket': AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter(
                # Original chat connection
                chat.routing.websocket_urlpatterns +
                # Second chat connection
                chat2.routing.websocket_urlpatterns
            )
        ),
    ),
})
Run Code Online (Sandbox Code Playgroud)

这允许您将特定 URL 的路由留给应用程序中的特定使用者,而不是项目routing文件。教程只是简单地指向了chat.routing.websocket_urlpatterns哪个是列表paths或者urls直接。您可以连接这些列表以构建您的整体项目路由结构,这就是我上面用+.

我假设这是必需的(并且与 Django URL 不同),因为 URLRouter 需要一个列表,而 Django urls ( include('path.to.url')) 可以使用项目 URLs 文件中的列表列表。


Nag*_*tri 6

根据他们的实现和文档(在此),的值ProtocolTypeRouter是map / dict,他们监听或查看的全部是两种类型的键:

ProtocolTypeRouter({
   "http": some_app,
   "websocket": some_other_app,
})
Run Code Online (Sandbox Code Playgroud)

这带来了一个事实,即如果您传递不同的密钥websocket02,它将无法正常工作。显然,这意味着必须有一种方法可以通过相同的websocket组合两个APP网址并创建单独的终结点。

实际上,您可以做的是,就像他们提到的那样:

from django.conf.urls import url

from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack

application = ProtocolTypeRouter({

    # WebSocket chat handler
    "websocket": AuthMiddlewareStack(
        URLRouter([
            url(r"^first_application/stream/$", app_2_consumers.AsyncApp1Consumer),
            url(r"^second_application/stream/$", app_2_consumers.AsyncApp2Consumer),
        ])
    ),

})
Run Code Online (Sandbox Code Playgroud)

上面的示例基于两个端点(在此处)的实现:

application = ProtocolTypeRouter({

    # WebSocket chat handler
    "websocket": AuthMiddlewareStack(
        URLRouter([
            url(r"^chat/admin/$", AdminChatConsumer),
            url(r"^chat/$", PublicChatConsumer),
        ])
    ),
})
Run Code Online (Sandbox Code Playgroud)

要么

在同一websocket下基于不同渠道的路线:https : //github.com/django/channels/blob/master/docs/topics/routing.rst#channelnamerouter