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

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缓存功能可正常存取数据,不存在端口未开放问题
问题根因与修复方案

核心错误点

  1. 端口配置不匹配:业务缓存用的Redis端口是49153,但CHANNEL_LAYERS初始配置写的是49155,端口错误直接导致连接被拒绝。
  2. channels-redis连接格式错误:使用元组格式("default:redispw@127.0.0.1", 49155)传参时,channels-redis会把元组第一个元素完全当作主机地址解析,不会自动拆分前缀里的账号密码,系统会尝试把default:redispw@127.0.0.1当作域名解析,直接触发getaddrinfo failed报错。后续修改时把URL和端口用逗号拆分写的格式也不符合解析规则,所以错误没有解决。
  3. 异步调用漏写await:Consumer最后一行self.send(...)是异步方法,前面没有加await,即使Redis连接正常,这里也会抛出协程未等待的错误。另外直接调用self.send()时不需要套websocket.send的type结构,这个格式是channel_layer组播时才需要用的。

修复步骤

  1. 修正CHANNEL_LAYERS配置,直接使用和缓存配置一致的标准Redis URL格式,不要用拆分元组的方式传递认证信息,末尾指定数据库编号避免和其他缓存数据冲突:
    CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels_redis.core.RedisChannelLayer",
            "CONFIG": {
                "hosts": ["redis://default:redispw@127.0.0.1:49153/0"],
            },
        },
    }
    
  2. 修正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"
            }))
    
  3. 保存修改后重启Django服务,再测试Websocket连接即可正常通信。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 16:01:02