在django通道中使用redischannellayer时,长url(包括密钥)导致unicode idna编解码器解码错误

sqyvllje  于 2021-06-10  发布在  Redis
关注(0)|答案(1)|浏览(650)

我在heroku上部署django频道时遇到了一个问题,同时使用了redischannellayer。
我得到一个 UnicodeError: encoding with 'idna' codec failed (UnicodeError: label empty or too long) 在连接过程中(下面是完整的回溯)。
这似乎是一个与主机地址中的一个标签过长有关的问题,如本期python所示。
我从我的消费者那里打印了一些信息,还 Package 了python的 socket.getaddrinfo 显示主机和连接信息的模块。
这个相关的帖子在连接shopify时遇到了同样的问题,而不是redis示例,他们通过在请求头中放置凭证来解决这个问题。但我无法控制 channels_redis 或者 asyncio .
有什么线索吗?

django渠道消费者的属性:

.组 [] .channel\u层 RedisChannelLayer(hosts=[{'address': ('h:alongkeycomprisingof65charsintotalx@ec2-18-202-152-61.eu-west-1.compute.amazonaws.com', '9759')}]) .channel\u名称 specific.OSfTzyqY!pdvgHnaCxWiv .房间名称 8e3d3083-8bb1-4d85-89d3-4496d9b9e946 .房间\组\名称 twined_8e3d3083-8bb1-4d85-89d3-4496d9b9e946 ####完全回溯:

Traceback (most recent call last):
 File "/app/.heroku/python/lib/python3.6/site-packages/channels/sessions.py", line 183, in __call__
 return await self.inner(receive, self.send)
 File "/app/.heroku/python/lib/python3.6/site-packages/channels/middleware.py", line 41, in coroutine_call
 await inner_instance(receive, send)
 File "/app/.heroku/python/lib/python3.6/site-packages/channels/consumer.py", line 59, in __call__
 [receive, self.channel_receive], self.dispatch
 File "/app/.heroku/python/lib/python3.6/site-packages/channels/utils.py", line 51, in await_many_dispatch
 await dispatch(result)
 File "/app/.heroku/python/lib/python3.6/site-packages/channels/consumer.py", line 73, in dispatch
 await handler(message)
 File "/app/.heroku/python/lib/python3.6/site-packages/channels/generic/websocket.py", line 175, in websocket_connect
 await self.connect()
 File "/app/backend/pink/consumers.py", line 24, in connect
 await self.channel_layer.group_add(self.room_group_name, self.channel_name)
 File "/app/.heroku/python/lib/python3.6/site-packages/channels_redis/core.py", line 589, in group_add
 async with self.connection(self.consistent_hash(group)) as connection:
 File "/app/.heroku/python/lib/python3.6/site-packages/channels_redis/core.py", line 835, in __aenter__
 self.conn = await self.pool.pop()
 File "/app/.heroku/python/lib/python3.6/site-packages/channels_redis/core.py", line 73, in pop
 conns.append(await aioredis.create_redis(**self.host, loop=loop))
 File "/app/.heroku/python/lib/python3.6/site-packages/aioredis/commands/__init__.py", line 175, in create_redis
 loop=loop)
 File "/app/.heroku/python/lib/python3.6/site-packages/aioredis/connection.py", line 113, in create_connection
 timeout)
 File "/app/.heroku/python/lib/python3.6/asyncio/tasks.py", line 339, in wait_for
 return (yield from fut)
 File "/app/.heroku/python/lib/python3.6/site-packages/aioredis/stream.py", line 24, in open_connection
 lambda: protocol, host, port,**kwds)
 File "/app/.heroku/python/lib/python3.6/asyncio/base_events.py", line 750, in create_connection
 infos = f1.result()
 File "/app/.heroku/python/lib/python3.6/concurrent/futures/thread.py", line 56, in run
 result = self.fn(*self.args,**self.kwargs)
 File "./backend/amy/asgi.py", line 69, in mygetaddrinfo
 for res in socket._socket.getaddrinfo(host, port, family, type, proto, flags):
 UnicodeError: encoding with 'idna' codec failed (UnicodeError: label empty or too long)
xmd2e60i

xmd2e60i1#

我可以通过建立 RedisChannelLayer 用论据口述 create_connection (如本文所述,不是提供很长的主机名。
通过手动解析heroku提供给我的redis\uurl变量中的密码,并重建 host 如果没有uri,我可以将该密码作为单独的字段添加到 create_connection dict,将主机字符串长度保持在64个字符以下。
我用我的时间做这个 settings.py 文件,现在看起来像:

def parse_redis_url(url):
    """ parses a redis url into component parts, stripping password from the host.
    Long keys in the url result in parsing errors, since labels within a hostname cannot exceed 64 characters under
    idna rules.
    In that event, we remove the key/password so that it can be passed separately to the RedisChannelLayer.
    Heroku REDIS_URL does not include the DB number, so we allow for a default value of '0'
    """
    parsed = urlparse(url)
    parts = parsed.netloc.split(':')
    host = ':'.join(parts[0:-1])
    port = parts[-1]
    path = parsed.path.split('/')[1:]
    db = int(path[0]) if len(path) >= 1 else 0

    user, password = (None, None)
    if '@' in host:
        creds, host = host.split('@')
        user, password = creds.split(':')
        host = f'{user}@{host}'

    return host, port, user, password, db

REDIS_URL = env('REDIS_URL', default='redis://localhost:6379')
REDIS_HOST, REDIS_PORT, REDIS_USER, REDIS_PASSWORD, REDIS_DB = parse_redis_url(REDIS_URL)

# DJANGO CHANNELS

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [{
                'address': f'redis://{REDIS_HOST}:{REDIS_PORT}',
                'db': REDIS_DB,
                'password': REDIS_PASSWORD,
            }],
        },
    },
}

相关问题