Django+Next.js实时聊天项目:Channels依赖未识别及WebSocket连接失败求助
Django + Next.js 实时聊天项目问题排查与解决
问题描述
1. Channels 包导入与环境依赖异常
已安装channels和channels-redis,但代码中import channels.db无法被解析,requirements.txt显示这两个包未在当前环境中安装,使用virtualenv和poetry创建环境均出现该问题。
2. WebSocket 连接失败
前端尝试连接后端时,报错WebSocket connection to 'ws://127.0.0.1:8000/' failed,切换为ws://localhost:8000/后问题依旧。
项目相关代码
settings.py
WSGI_APPLICATION = 'backend.wsgi.application' ASGI_APPLICATION = "backend.asgi.application" CHANNEL_LAYERS = { 'default': { 'BACKEND': "channels_redis.core.RedisChannelLayer", "CONFIG": { "hosts": [("redis", "6379")], }, } }
asgi.py
import os from django.core.asgi import get_asgi_application from channels.routing import ProtocolTypeRouter, URLRouter from channels.auth import AuthMiddlewareStack from . import routing os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') django_asgi_app = get_asgi_application() # application = get_asgi_application() application = ProtocolTypeRouter({ "http": django_asgi_app, "websocket": AuthMiddlewareStack( URLRouter( routing.websocket_urlpatterns ) ), })
routing.py
from django.urls import re_path from chat.consumers import ChatConsumer websocket_urlpatterns = [ re_path(r'ws/chat/', ChatConsumer.as_asgi()), ]
consumers.py
import json from channels.generic.websocket import AsyncWebsocketConsumer from channels.layers import get_channel_layer from channels.db import database_sync_to_async from .models import Message class ChatConsumer(AsyncWebsocketConsumer): async def connect(self): self.room_group_name = 'chat' await self.channel_layer.group_add( self.room_group_name, self.channel_name ) await self.accept() async def disconnect(self, close_code): await self.channel_layer.group_discard( self.room_group_name, self.channel_name ) @database_sync_to_async def create_message(self, message, username): message_obj = Message.objects.create( content=message, username=username ) return message_obj async def receive(self, text_data): data = json.loads(text_data) message = data['message'] username = data['username'] # Create a new message object and save it to the database message_obj = await self.create_message(message, username) # Send the message to the group await self.channel_layer.group_send( self.room_group_name, { 'type': 'chat_message', 'message': message_obj.content, 'username': message_obj.username, 'timestamp': str(message_obj.timestamp) } ) async def chat_message(self, event): message = event['message'] username = event['username'] timestamp = event['timestamp'] # Send the message to the websocket await self.send(text_data=json.dumps({ 'message': message, 'username': username, 'timestamp': timestamp }))
前端代码(Next.js)
import { useState, useEffect } from "react"; import useWebSocket, { ReadyState } from "react-use-websocket"; const ChatEngine = (props) => { const [showChat, setShowChat] = useState(false); const [socket, setSocket] = useState(null); const [username, setUsername] = useState(""); const [email, setEmail] = useState(""); const [message, setMessage] = useState(""); const [messages, setMessages] = useState([]); const [welcomeMessage, setWelcomeMessage] = useState(""); const { readyState } = useWebSocket("ws://127.0.0.1:8000/", { onOpen: () => { console.log("Connected!"); }, onClose: () => { console.log("Disconnected!"); }, // New onMessage handler onMessage: (e) => { console.log(e); }, }); const connectionStatus = { [ReadyState.CONNECTING]: "Connecting", [ReadyState.OPEN]: "Open", [ReadyState.CLOSING]: "Closing", [ReadyState.CLOSED]: "Closed", [ReadyState.UNINSTANTIATED]: "Uninstantiated", }[readyState]; console.log("connection status: ", connectionStatus);
问题解决方案
问题1:Channels 包导入与环境依赖异常
- 校验环境与包安装状态
- 激活对应环境后,执行
pip list(virtualenv)或poetry show(poetry),确认channels和channels-redis是否存在。 - 若未安装,virtualenv环境下执行
pip install channels channels-redis;poetry环境下执行poetry add channels channels-redis。
- 激活对应环境后,执行
- 修正依赖文件生成方式
- virtualenv环境:安装完成后执行
pip freeze > requirements.txt更新依赖列表。 - poetry环境:执行
poetry export -f requirements.txt --output requirements.txt --without-hashes生成标准requirements文件。
- virtualenv环境:安装完成后执行
- 版本兼容校验
若导入仍报错,尝试安装稳定版本:pip install channels==4.0.0 channels-redis==4.1.0,避免版本迭代导致的模块路径变更。
问题2:WebSocket 连接失败
- 修正前端连接路径
后端路由配置的WebSocket路径为ws/chat/,前端需对应修改连接URL:const { readyState } = useWebSocket("ws://127.0.0.1:8000/ws/chat/", { // 原有配置保留 }); - 使用ASGI模式启动后端
Django默认runserver需开启ASGI模式支持WebSocket:
或使用Daphne服务器启动:python manage.py runserver --asgidaphne backend.asgi:application - Redis服务与配置校验
- 本地开发时,将CHANNEL_LAYERS中的主机名改为
127.0.0.1:CHANNEL_LAYERS = { 'default': { 'BACKEND': "channels_redis.core.RedisChannelLayer", "CONFIG": { "hosts": [("127.0.0.1", "6379")], }, } } - 执行
redis-cli ping确认Redis服务正常运行,返回PONG则服务正常。
- 本地开发时,将CHANNEL_LAYERS中的主机名改为
- 跨域配置(端口不一致时)
若Next.js运行在3000端口,Django在8000端口,需配置跨域:- 安装
django-cors-headers:pip install django-cors-headers - 修改settings.py:
INSTALLED_APPS = [ # 其他应用 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', # 其他中间件 ] CORS_ALLOW_ALL_ORIGINS = True # 开发环境临时配置,生产环境需指定域名 CORS_ALLOW_CREDENTIALS = True - 为WebSocket添加主机校验:
from channels.security.websocket import AllowedHostsOriginValidator application = ProtocolTypeRouter({ "http": django_asgi_app, "websocket": AllowedHostsOriginValidator( AuthMiddlewareStack( URLRouter( routing.websocket_urlpatterns ) ) ), })
- 安装
内容的提问来源于stack exchange,提问作者phanio
相关产品推荐
相关产品推荐

