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);
};
Я нашел его! Или, по крайней мере, мне так кажется. Начиная с 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/'
.