WebSocket connection to 'wss://example.com/wss/' failed in Django Channels

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);
};

enter image description here

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.

© 2024 Dagalaxy. All rights reserved.