WebSocket connection to 'wss://example.com/wss/' failed in Django Channels
I'm trying to set up a WebSocket connection using Django Channels in my Django project. However, I keep encountering an error when trying to connect from the frontend JavaScript. The error message in the browser console is:
WebSocket connection to 'wss://example.com/wss/' failed
Here is my project structure:
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
My settings.py includes:
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',
},
}
The asgi.py file is configured as follows:
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
)
),
})
My routing.py:
from django.urls import path
from . import consumers
websocket_urlpatterns = [
path('wss/', consumers.LoadConsumer.as_asgi()),
]
The consumer class in 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
And here is the JavaScript code for the WebSocket connection:
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);
};
Edit
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path('ws/', consumers.LoadConsumer.as_asgi()),
]
Answer
I found it! Or at least I think I did. Starting in Django 2.0, path()
was introduced as a simpler way to write URL paths in Django. Unfortunately this doesn’t provide everything Django Channels needs to provide routing. In their own words:
Note we use
re_path()
due to limitations in URLRouter.
I have no idea what limitations they encountered but it is plausible because even the Django team acknowledges that path()
is a simpler interface while re_path()
is for finer control and more versatility.
Most people actually make this mistake too so you are not alone in this. [1]
Change your code from using path()
to using re_path()
and you will be fine.
[1] Here [github] is one such case posited in the answer.