Django Channels报错socket.gaierror: getaddrinfo failed
问题描述
我正在使用Django Channels搭建Websocket功能,计划在对应API端点触发时发送测试消息。但使用Postman测试websocket连接时,虽可成功建立连接、接收到我发送的JSON数据,但连接会立即断开,完整报错追踪如下:
redis.exceptions.ConnectionError: Error 10061 connecting to localhost:49155. No connection could be made because the target machine actively refused it. HTTP GET /media/profile/2022/06/10/photo-1615672968435-95ade28e0b38.jpg 500 [4.47, 127.0.0.1:51105] HTTP GET /users/1/ 500 [4.46, 127.0.0.1:51106] WebSocket HANDSHAKING /stories/notification_testing/ [127.0.0.1:50570] {'type': 'websocket', 'path': '/stories/notification_testing/', 'raw_path': b'/stories/notification_testing/', 'headers': [(b'sec-websocket-version', b'13' ), (b'sec-websocket-key', b'TcKbMvNYlHQtJdO5efSXDQ=='), (b'connection', b'Upgrade'), (b'upgrade', b'websocket'), (b'sec-websocket-extensions', b'permessage deflate; client_max_window_bits'), (b'host', b'127.0.0.1:8000')], 'query_string': b'', 'client': ['127.0.0.1', 50570], 'server': ['127.0.0.1', 8000], 'sub protocols': [], 'asgi': {'version': '3.0'}, 'cookies': {}, 'session': <django.utils.functional.LazyObject object at 0x00000207DC59A5E0>, 'user': <channels.auth.UserLazyObject object at 0x00000207D8D5A820>, 'path_remaining': '', 'url_route': {'args': (), 'kwargs': {}}} WebSocket CONNECT /stories/notification_testing/ [127.0.0.1:50570] Exception inside application: [Errno 11003] getaddrinfo failed Traceback (most recent call last): ... File "C:\Users\15512\Desktop\django-project\peerplatform\signup\consumers.py", line 31, in websocket_connect await self.channel_layer.group_add(self.room_group_name, self.channel_name) ... for res in _socket.getaddrinfo(host, port, family, type, proto, flags): socket.gaierror: [Errno 11003] getaddrinfo failed WebSocket DISCONNECT /stories/notification_testing/ [127.0.0.1:50570]
我通过Docker镜像运行Redis服务,当前该Redis实例已用于其他业务的缓存,可正常存取数据。Settings.py中配置的Channels层如下:
CHANNEL_LAYERS = { "default": { "BACKEND": "channels_redis.core.RedisChannelLayer", "CONFIG": { "hosts": [("default:redispw@127.0.0.1", 49155)], }, }, }
Docker中运行的Redis实例的缓存配置地址为:
"LOCATION": "redis://default:redispw@localhost:49153",
asgi.py中配置的websocket路由如下:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'signup.settings') application = ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": AuthMiddlewareStack( URLRouter( [path('stories/notification_testing/', NotificationConsumer.as_asgi())] )) })
报错指向consumers.py文件第31行,对应NotificationConsumer类的websocket_connect方法代码如下:
class NotificationConsumer(AsyncWebsocketConsumer): async def websocket_connect(self, event): print(self.scope) await self.accept() await self.send(json.dumps({ "type": "websocket.send", "text": "hello world" })) self.room_name='test_consumer' self.room_group_name='test_consumer_group' await self.channel_layer.group_add(self.room_group_name, self.channel_name) self.send({ "type": "websocket.send", "text": "room made" })
相关models.py代码如下:
class Notifications(models.Model): sender = models.ForeignKey(User, null=True, blank=True, related_name='sender', on_delete=models.CASCADE) receiver = models.ForeignKey(User, null=True, blank=True, related_name='receiver', on_delete=models.CASCADE) status = models.CharField(max_length=264, null=True, blank=True, default="unread") type_of_notification = models.CharField(max_length=264, null=True, blank=True)
已尝试的排查方案
- 查阅资料后将host修改为
redis://default:redispw@localhost, 49153,仍出现相同错误 - 重新安装所有
django-channels与channels-redis依赖 - 临时关闭防火墙排查是否为拦截导致的问题
- 确认Redis服务的主机与端口已正常暴露,当前使用的Redis缓存功能可正常存取数据,不存在端口未开放问题
问题根因与修复方案
核心错误点
- 端口配置不匹配:业务缓存用的Redis端口是49153,但CHANNEL_LAYERS初始配置写的是49155,端口错误直接导致连接被拒绝。
- channels-redis连接格式错误:使用元组格式
("default:redispw@127.0.0.1", 49155)传参时,channels-redis会把元组第一个元素完全当作主机地址解析,不会自动拆分前缀里的账号密码,系统会尝试把default:redispw@127.0.0.1当作域名解析,直接触发getaddrinfo failed报错。后续修改时把URL和端口用逗号拆分写的格式也不符合解析规则,所以错误没有解决。 - 异步调用漏写await:Consumer最后一行
self.send(...)是异步方法,前面没有加await,即使Redis连接正常,这里也会抛出协程未等待的错误。另外直接调用self.send()时不需要套websocket.send的type结构,这个格式是channel_layer组播时才需要用的。
修复步骤
- 修正CHANNEL_LAYERS配置,直接使用和缓存配置一致的标准Redis URL格式,不要用拆分元组的方式传递认证信息,末尾指定数据库编号避免和其他缓存数据冲突:
CHANNEL_LAYERS = { "default": { "BACKEND": "channels_redis.core.RedisChannelLayer", "CONFIG": { "hosts": ["redis://default:redispw@127.0.0.1:49153/0"], }, }, } - 修正Consumer代码,补全缺失的await,调整send方法的参数格式:
class NotificationConsumer(AsyncWebsocketConsumer): async def websocket_connect(self, event): print(self.scope) await self.accept() await self.send(text_data=json.dumps({ "text": "hello world" })) self.room_name='test_consumer' self.room_group_name='test_consumer_group' await self.channel_layer.group_add(self.room_group_name, self.channel_name) # 补await,修正send传参格式 await self.send(text_data=json.dumps({ "text": "room made" })) - 保存修改后重启Django服务,再测试Websocket连接即可正常通信。
内容的提问来源于stack exchange,提问作者Emm
相关产品推荐
相关产品推荐

