Django应用WebSocket连接失败,终端报404错误求解决
Django WebSocket连接失败排查与解决
问题现象
WebSocket连接失败,错误信息:WebSocket connection to 'ws://localhost:8000/ws/chat/cujncvifd/' failed,终端输出Not Found: /ws/chat/cujncvifd/。
相关代码片段
settings.py
INSTALLED_APPS = [ 'channels', 'common_anime_chat.apps.CommonAnimeChatConfig', 'users.apps.UsersConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] ASGI_APPLICATION = 'anime_chat_app.routing.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 import common_anime_chat.routing os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'anime_chat_app.settings') #the new code about the application you told me to write
主项目目录 routing.py
from channels.auth import AuthMiddlewareStack from channels.routing import ProtocolTypeRouter, URLRouter from django.core.asgi import get_asgi_application from channels.security.websocket import AllowedHostsOriginValidator import common_anime_chat.routing application = ProtocolTypeRouter({ 'websocket':AuthMiddlewareStack( URLRouter( common_anime_chat.routing.websocket_urlpatterns ) ), "http":get_asgi_application(), })
common_anime_chat应用 routings.py
from django.urls import re_path from . import consumers websocket_urlpatterns = [ re_path(r'^ws/chat/(?P<room_name>\w+)/$', consumers.ChatRoomConsumer.as_asgi()) ]
consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer import json class ChatRoomConsumer(AsyncWebsocketConsumer): async def connect(self): self.room_name = self.scope['url_route']['kwargs']['room_name'] self.room_group_name = 'chat_%s' % self.room_name await self.channel_layer.group_add( self.room_group_name, self.channel_name ) await self.accept() await self.channel_layer.group_send( self.room_group_name, { 'type':'tester_message', 'tester':'hello world' } ) async def tester_message(self, event): tester = event['tester'] await self.send(text_data=json.dumps({ 'tester':tester, })) async def disconnect(self, close_code): await self.channel_layer.group_discard( self.room_group_name, self.channel_name )
common_anime_chat/urls.py
from django.urls import path from . import views urlpatterns = [ path('', views.home, name='common-anime-chat-home'), path('about/', views.about, name='common-anime-chat-about'), path('chat/<str:room_name>/', views.room, name='room'), ]
chatroom.html
{% extends 'common_anime_chat/base.html' %} {% load static %} {% block stylesheet %} <link rel="stylesheet" type="text/css" href="{% static 'chatroom.css' %}"> {% endblock stylesheet %} {% block content %} <div id="user-hello"></div> {{ room_name|json_script:"room-name" }} <script> const roomName = JSON.parse(document.getElementById('room-name').textContent); console.log(roomName) const chatSocket = new WebSocket( 'ws://' + window.location.host + '/ws/chat/'+ roomName + '/' ); chatSocket.onmessage = function (e) { const data = JSON.parse(e.data); document.querySelector('#user-hello').innerHTML = (data.tester); }; </script> {% endblock content %}
已尝试的解决方案
- 在common_anime_chat的routings.py中切换"ws://"与"ws/"
- 在模板的WebSocket连接代码中移除"ws"
- 关闭防火墙
- 重启服务器,更新Django和Channels至最新版本
排查与解决步骤
1. 修复路由文件名不匹配问题
主项目routing.py中导入的是common_anime_chat.routing,但你的应用中WebSocket路由文件名为routings.py(多了一个s),这是导致路由无法被找到的核心原因。
- 方案一:将
common_anime_chat应用中的routings.py重命名为routing.py - 方案二:修改主项目
routing.py中的导入语句和引用:import common_anime_chat.routings application = ProtocolTypeRouter({ 'websocket':AuthMiddlewareStack( URLRouter( common_anime_chat.routings.websocket_urlpatterns ) ), "http":get_asgi_application(), })
2. 修正ASGI应用配置
当前asgi.py未正确导出Channels应用实例,修改为:
import os os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'anime_chat_app.settings') # 直接复用主项目的路由配置 from anime_chat_app.routing import application
3. 调整WebSocket路由正则匹配规则
如果room_name包含下划线、字母、数字以外的字符(比如连字符),原正则\w+无法匹配,修改为兼容性更强的规则:
websocket_urlpatterns = [ re_path(r'^ws/chat/(?P<room_name>[^/]+)/$', consumers.ChatRoomConsumer.as_asgi()) ]
[^/]+表示匹配除斜杠外的任意字符,覆盖更多room_name场景。
4. 修正消费者中的错误方法
消费者disconnect方法中使用了错误的方法名,Channels中正确的移除分组方法是group_remove,修改为:
async def disconnect(self, close_code): await self.channel_layer.group_remove( self.room_group_name, self.channel_name )
5. 确保用正确方式启动服务器
使用Channels兼容的ASGI服务器启动项目,直接运行:
python manage.py runserver
若使用Daphne,先安装再启动:
pip install daphne daphne anime_chat_app.asgi:application
内容的提问来源于stack exchange,提问作者user21744561
相关产品推荐
相关产品推荐

