Desiigner
Desiigner

Reputation: 2316

django-channels: No route found for path

I have a Django + Vue.js chat application that I'm trying to connect to django-channels.

To access any chat room, you simply go to:

http://localhost:8080/rooms/"id"/

My javascript connection looks like this:

connectToWebSocket () {
  const chatSocket = new WebSocket(
    `ws://localhost:8000/ws/rooms/${this.$route.params.id}/`
  )

  chatSocket.onopen = this.onOpen
  chatSocket.onclose = this.onClose
  chatSocket.onmessage = this.onMessage
  chatSocket.onerror = this.onError
},

My consumers.py:

class ChatConsumer(WebsocketConsumer):
def connect(self):
    self.room_uri = self.scope['url_route']['kwargs']['uri']
    self.room_group_name = 'chat_%s' % self.room_uri

    # Join room group
    async_to_sync(self.channel_layer.group_add)(
        self.room_group_name,
        self.channel_name
    )

    self.accept()

def disconnect(self, close_code):
    # Leave room group
    async_to_sync(self.channel_layer.group_discard)(
        self.room_group_name,
        self.channel_name
    )

# Receive message from WebSocket
def receive(self, text_data):
    text_data_json = json.loads(text_data)
    message = text_data_json['message']
    user = text_data_json['user.username']

    # Send message to room group
    async_to_sync(self.channel_layer.group_send)(
        self.room_group_name,
        {
            'type': 'chat_message',
            'user': user,
            'message': message
        }
    )

# Receive message from room group
def chat_message(self, event):
    user = event['user']
    message = event['message']

    # Send message to WebSocket
    self.send(text_data=json.dumps({
        'user': user,
        'message': message
    }))

and my routing.py:

from django.conf.urls import url

from core import consumers


websocket_urlpatterns = [
    url(r'^ws/rooms/<uri>/', consumers.ChatConsumer),
]

my project routing.py:

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

import core.routing


application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter(
            core.routing.websocket_urlpatterns
        )
    )
})

The problem is, I can't connect to the websocket, my django server says:

[Failure instance: Traceback: : No route found for path 'ws/rooms/759b9a8262ea4b7/'.

What's wrong in my code that I can't connect to a specific room through the websocket?

Full stack trace:

[Failure instance: Traceback: : No route found for path 'ws/rooms/759b9a8262ea4b7/'. /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/autobahn/websocket/protocol.py:2801:processHandshake /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/txaio/tx.py:429:as_future /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/twisted/internet/defer.py:151:maybeDeferred /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/daphne/ws_protocol.py:82:onConnect --- --- /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/twisted/internet/defer.py:151:maybeDeferred /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/daphne/server.py:198:create_application /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/channels/staticfiles.py:41:call /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/channels/routing.py:58:call /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/channels/sessions.py:43:call /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/channels/sessions.py:141:call /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/channels/sessions.py:165:init /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/channels/middleware.py:31:call /home/dave/PycharmProjects/chatapp2/back/venv/lib/python3.6/site-packages/channels/routing.py:154:call

Upvotes: 16

Views: 29360

Answers (9)

lator
lator

Reputation: 335

If anyone is facing this issue, check the trailing slashes in the url in your JavaScript or in the websocket_urlpatterns. Make sure they're the same.

Upvotes: 0

Raj Patel
Raj Patel

Reputation: 109

I spent like more than an hour to this problem and I found out that django project my default doesn't take asgi.py configuration settings in consideration.

  1. Install daphne into your project
    python -m pip install daphne

  2. list into your INSTALLED_APPS array

INSTALLED_APPS = [
    "daphne",
    ...,
]
  1. Mentioned asgi application object

ASGI_APPLICATION = "myproject.asgi.application"

Run your project and see if it connects with your websocket.

For context, my asgi.py file is like this

import os

from django.core.asgi import get_asgi_application
from django.urls import path
from channels.routing import ProtocolTypeRouter, URLRouter

from chat_app.routing import ChatConsumer


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

websocket_urlpatterns = [
    path('ws/chat', ChatConsumer.as_asgi())
]

application = ProtocolTypeRouter(
    {
        "http": get_asgi_application(),
        "websocket": URLRouter(websocket_urlpatterns),
    }
)

Upvotes: 1

Giannis Katsini
Giannis Katsini

Reputation: 1289

Try something like this:

routing.py (Inside your django app folder)

from django.urls import path
from core import consumers

websocket_urlpatterns = [
    path('ws/rooms/<uri>/', consumers.ChatConsumer),
]

routing.py (Same level as your settings.py)

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

application = ProtocolTypeRouter({
    # (http->django views is added by default)
    'websocket': AuthMiddlewareStack(
        URLRouter(
            myapp.routing.websocket_urlpatterns
        )
    ),
})

And lastly in your settings.py

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [REDIS_URL],
        },
    },
}

INSTALLED_APPS.append('channels')
ASGI_APPLICATION = 'myapp.routing.application'

Upvotes: 8

Leon Mu
Leon Mu

Reputation: 1

you may need to restart the services, seems it would not automatic reload.

Upvotes: 0

Romeo
Romeo

Reputation: 788

To anyone new that may be facing this issue. Don't use the path pattern matcher with a regular expression. If you wish to do use, use either url or re_path instead.

using path

Match pattern without trailing or leading slash (/) and make sure pattern corresponds with client web socket URL

websocket_urlpatterns = [
    path("ws/chat/<int:uri>", ChatConsumer.as_asgi()),
]

Using re_path or url

Match pattern without trailing slash (/).

url(r'^ws/chat/(?P<uri>[^/]+)/$', ChatConsumer.as_asgi()),

NOTE: I advise using path because it's easier to match patterns and read.

Upvotes: 2

Victor Joseph
Victor Joseph

Reputation: 39

i had similar issue and added .as_asgi() and it worked

url(r"messages/(?P<username>[\w.@+-]+)/", ChatConsumer.as_asgi()),

Upvotes: 0

Ali H. Kudeir
Ali H. Kudeir

Reputation: 1054

Removing the slash from the app.routing routes file solved the problem, I guess it was being counted a duplicate slash in the URL of that socket.

For instance, I had:

url(r'/ws/documents/get-df', consumers.DFConsumer.as_asgi())

This was not working, but it worked when I removed the first slash before was

url(r'ws/documents/get-df', consumers.DFConsumer.as_asgi())

Upvotes: 1

juan aparicio
juan aparicio

Reputation: 151

You need to use url, I had the same problem:

Not working

websocket_urlpatterns = [
  path('ws/chat/<str:room_name>/$', consumers.ChatConsumer),
]

Working

websocket_urlpatterns = [
   url(r'^ws/chat/(?P<room_name>[^/]+)/$', consumers.ChatConsumer),
]

Upvotes: 15

LittleCabbage
LittleCabbage

Reputation: 71

I met the same problem as you,and just now I happened to solve it! in my ws_client.py I wrote this

ws.create_connection("ws://127.0.0.1:8000/alarm")

and in routing.py I changed to this below and it worked

from django.urls import path
channel_routing = [
    path('alarm',consumers.ws_message),
    # before I wrote 'alarm/', I just change from alarm/ to alarm
]

and it worked! you can try it

Upvotes: 6

Related Questions