WebSocket-соединение с 'wss://example.com/wss/' не удалось в Django Channels

Я пытаюсь установить WebSocket соединение с помощью Django Channels в моем Django проекте. Однако я постоянно сталкиваюсь с ошибкой при попытке подключения из фронтенда JavaScript. Сообщение об ошибке в консоли браузера выглядит так:

WebSocket connection to 'wss://example.com/wss/' failed

Вот структура моего проекта:

project/
    ├── myproject/
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   ├── wsgi.py
    │   ├── asgi.py
    ├── myapp/
    │   ├── __init__.py
    │   ├── views.py
    │   ├── urls.py
    │   ├── consumers.py
    │   ├── routing.py
    │   ├── templates/
    │       ├── index.html
    ├── manage.py
    ├── passenger_wsgi.py
    ├── requirements.txt

Мой файл settings.py включает:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'channels',
]

ASGI_APPLICATION = 'myproject.asgi.application'

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels.layers.InMemoryChannelLayer',
    },
}

Файл asgi.py настроен следующим образом:

import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import myapp.routing

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket": AuthMiddlewareStack(
        URLRouter(
            myapp.routing.websocket_urlpatterns
        )
    ),
})

Мой routing.py:

from django.urls import path
from . import consumers

websocket_urlpatterns = [
    path('wss/', consumers.LoadConsumer.as_asgi()),
]

Класс потребителя в consumers.py:

from channels.generic.websocket import AsyncWebsocketConsumer

class LoadConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()

    async def disconnect(self, close_code):
        pass

    async def receive(self, text_data):
        pass

А вот код JavaScript для соединения WebSocket:

const socket = new WebSocket('wss://example.com/wss/');

socket.onopen = function(event) {
    console.log("WebSocket is open now.");
};

socket.onmessage = function(event) {
    console.log("WebSocket message received:", event);
};

socket.onclose = function(event) {
    console.log("Connection closed");
};

socket.onerror = function(error) {
    console.log("WebSocket Error:", error);
};

enter image description here

Я нашел его! Или, по крайней мере, мне так кажется. Начиная с Django 2.0, path() был представлен как более простой способ написания URL-путей в Django. К сожалению, это не дает всего того, что нужно Django Channels для обеспечения маршрутизации. По их собственным словам:

Обратите внимание, что мы используем re_path() из-за ограничений в URLRouter.

Я понятия не имею, с какими ограничениями они столкнулись, но это вполне правдоподобно, поскольку даже команда Django признает, что path() - это более простой интерфейс, а re_path() - для более тонкого управления и большей универсальности.

Most people actually make this mistake too so you are not alone in this. [1]

Измените свой код с использования path() на использование re_path(), и все будет в порядке.


[1] Here [github] is one such case posited in the answer.

Add 'daphne' to the top of the INSTALLED_APPS setting, not 'channels'.
Tutorial: https://channels.readthedocs.io/en/latest/tutorial/part_1.html#integrate-the-channels-library

INSTALLED_APPS = [
    'daphne',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 'channels',
]

Также проверьте, что вы имели в виду: 'wss://example.com/wss/' (с вашим развернутым доменом) или 'wss://127.0.0.1:8000/wss/'.

Вернуться на верх