You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Django Channels搭建WebSocket聊天时出现Channel Name类型错误

Django Channels WebSocket聊天功能TypeError问题解决

问题描述

使用Django Channels搭建基础WebSocket实时聊天功能,网站加载正常,但进入站点时终端抛出如下TypeError:

TypeError: Channel name must be a valid unicode string with length < 100 containing only ASCII alphanumerics, hyphens, underscores, or periods, not RedisChannelLayer(hosts=[{'host': '127.0.0.1', 'port': 6379}])

怀疑问题出在settings.py中,但当前Channel Layer配置如下,未发现异常:

CHANNEL_LAYERS = {
    'default': {
        "BACKEND": 'channels_redis.core.RedisChannelLayer',
        "CONFIG": {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}

完整报错回溯

Exception inside application: Channel name must be a valid unicode string with length < 100 containing only ASCII alphanumerics, hyphens, underscores, or periods, not RedisChannelLayer(hosts=[{'host': '127.0.0.1', 'port': 6379}])
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/contrib/staticfiles/handlers.py", line 101, in __call__
    return await self.application(scope, receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/routing.py", line 62, in __call__
    return await application(scope, receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/security/websocket.py", line 37, in __call__
    return await self.application(scope, receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/sessions.py", line 47, in __call__
    return await self.inner(dict(scope, cookies=cookies), receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/sessions.py", line 263, in __call__
    return await self.inner(wrapper.scope, receive, wrapper.send)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/auth.py", line 185, in __call__
    return await super().__call__(scope, receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/middleware.py", line 24, in __call__
    return await self.inner(scope, receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/routing.py", line 116, in __call__
    return await application(
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/consumer.py", line 94, in app
    return await consumer(scope, receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/consumer.py", line 58, in __call__
    await await_many_dispatch(
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/utils.py", line 50, in await_many_dispatch
    await dispatch(result)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/consumer.py", line 73, in dispatch
    await handler(message)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/generic/websocket.py", line 173, in websocket_connect
    await self.connect()
  File "/Users/alecsmith/Documents/Python Work/ChatApp/chat/consumers.py", line 10, in connect
    await self.channel_layer.group_add(
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels_redis/core.py", line 518, in group_add
    assert self.valid_channel_name(channel), "Channel name not valid"
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/channels/layers.py", line 160, in valid_channel_name
    raise TypeError(self.invalid_name_error.format("Channel", name))
TypeError: Channel name must be a valid unicode string with length < 100 containing only ASCII alphanumerics, hyphens, underscores, or periods, not RedisChannelLayer(hosts=[{'host': '127.0.0.1', 'port': 6379}])

当前consumer.py代码

import json
from channels.generic.websocket import AsyncWebsocketConsumer

# Class tells websocket how it should be used when doing real time events betweeen computer and server
class ChatConsumer(AsyncWebsocketConsumer):
    # Accepts the connection of the websocket, makes a group name for the chatroom,
    # and add the group to the channel layer
    async def connect(self):
        self.roomGroupName = 'group_chat_gfg'
        await self.channel_layer.group_add(
            self.roomGroupName,
            self.channel_layer
        )
        await self.accept()
    
    # Removes the group name and removes the group itself from the channel layer
    async def disconnect(self):
        await self.channel_layer.group_discard(
            self.roomGroupName,
            self.channel_layer
        )
    
    # Recieves the message and spreads it to all other users in the chat room
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']
        username = text_data_json['username']
        await self.channel_layer.group_send(
            self.roomGroupName, {
                'type': 'sendMessage',
                'message': message,
                'username': username
            }
        )
    
    # Takes the name of the user and their message and sends it to the chat room
    async def sendMessage(self, event):
        message = event['message']
        username = event['username']
        await self.send(text_data = json.dumps({'message': message, 'username': username}))

问题原因及解决方案

问题出在ChatConsumer的connect和disconnect方法中:

  1. group_add和group_remove(原错误用了group_discard)的第二个参数应该是当前消费者的唯一通道名称(self.channel_name),你错误传入了通道层对象(self.channel_layer),导致不符合Channel名称格式要求。
  2. Channels中从组移除通道的标准方法是group_remove,而非group_discard。

修正后的ChatConsumer代码:

import json
from channels.generic.websocket import AsyncWebsocketConsumer

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.roomGroupName = 'group_chat_gfg'
        await self.channel_layer.group_add(
            self.roomGroupName,
            self.channel_name  # 替换为当前连接的通道名称
        )
        await self.accept()
    
    async def disconnect(self, close_code):
        await self.channel_layer.group_remove(  # 改用标准移除方法
            self.roomGroupName,
            self.channel_name  # 替换为当前连接的通道名称
        )
    
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']
        username = text_data_json['username']
        await self.channel_layer.group_send(
            self.roomGroupName, {
                'type': 'sendMessage',
                'message': message,
                'username': username
            }
        )
    
    async def sendMessage(self, event):
        message = event['message']
        username = event['username']
        await self.send(text_data = json.dumps({'message': message, 'username': username}))

解释:

  • self.channel_name是每个WebSocket连接对应的唯一标识,完全符合Channel Layer对名称格式的要求。
  • group_remove是Channels官方定义的从组中移除通道的方法,确保功能正常执行。

内容的提问来源于stack exchange,提问作者Alec Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 03:25:17