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

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

我在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 ####完全回溯:

  1. Traceback (most recent call last):
  2. File "/app/.heroku/python/lib/python3.6/site-packages/channels/sessions.py", line 183, in __call__
  3. return await self.inner(receive, self.send)
  4. File "/app/.heroku/python/lib/python3.6/site-packages/channels/middleware.py", line 41, in coroutine_call
  5. await inner_instance(receive, send)
  6. File "/app/.heroku/python/lib/python3.6/site-packages/channels/consumer.py", line 59, in __call__
  7. [receive, self.channel_receive], self.dispatch
  8. File "/app/.heroku/python/lib/python3.6/site-packages/channels/utils.py", line 51, in await_many_dispatch
  9. await dispatch(result)
  10. File "/app/.heroku/python/lib/python3.6/site-packages/channels/consumer.py", line 73, in dispatch
  11. await handler(message)
  12. File "/app/.heroku/python/lib/python3.6/site-packages/channels/generic/websocket.py", line 175, in websocket_connect
  13. await self.connect()
  14. File "/app/backend/pink/consumers.py", line 24, in connect
  15. await self.channel_layer.group_add(self.room_group_name, self.channel_name)
  16. File "/app/.heroku/python/lib/python3.6/site-packages/channels_redis/core.py", line 589, in group_add
  17. async with self.connection(self.consistent_hash(group)) as connection:
  18. File "/app/.heroku/python/lib/python3.6/site-packages/channels_redis/core.py", line 835, in __aenter__
  19. self.conn = await self.pool.pop()
  20. File "/app/.heroku/python/lib/python3.6/site-packages/channels_redis/core.py", line 73, in pop
  21. conns.append(await aioredis.create_redis(**self.host, loop=loop))
  22. File "/app/.heroku/python/lib/python3.6/site-packages/aioredis/commands/__init__.py", line 175, in create_redis
  23. loop=loop)
  24. File "/app/.heroku/python/lib/python3.6/site-packages/aioredis/connection.py", line 113, in create_connection
  25. timeout)
  26. File "/app/.heroku/python/lib/python3.6/asyncio/tasks.py", line 339, in wait_for
  27. return (yield from fut)
  28. File "/app/.heroku/python/lib/python3.6/site-packages/aioredis/stream.py", line 24, in open_connection
  29. lambda: protocol, host, port,**kwds)
  30. File "/app/.heroku/python/lib/python3.6/asyncio/base_events.py", line 750, in create_connection
  31. infos = f1.result()
  32. File "/app/.heroku/python/lib/python3.6/concurrent/futures/thread.py", line 56, in run
  33. result = self.fn(*self.args,**self.kwargs)
  34. File "./backend/amy/asgi.py", line 69, in mygetaddrinfo
  35. for res in socket._socket.getaddrinfo(host, port, family, type, proto, flags):
  36. 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 文件,现在看起来像:

  1. def parse_redis_url(url):
  2. """ parses a redis url into component parts, stripping password from the host.
  3. Long keys in the url result in parsing errors, since labels within a hostname cannot exceed 64 characters under
  4. idna rules.
  5. In that event, we remove the key/password so that it can be passed separately to the RedisChannelLayer.
  6. Heroku REDIS_URL does not include the DB number, so we allow for a default value of '0'
  7. """
  8. parsed = urlparse(url)
  9. parts = parsed.netloc.split(':')
  10. host = ':'.join(parts[0:-1])
  11. port = parts[-1]
  12. path = parsed.path.split('/')[1:]
  13. db = int(path[0]) if len(path) >= 1 else 0
  14. user, password = (None, None)
  15. if '@' in host:
  16. creds, host = host.split('@')
  17. user, password = creds.split(':')
  18. host = f'{user}@{host}'
  19. return host, port, user, password, db
  20. REDIS_URL = env('REDIS_URL', default='redis://localhost:6379')
  21. REDIS_HOST, REDIS_PORT, REDIS_USER, REDIS_PASSWORD, REDIS_DB = parse_redis_url(REDIS_URL)
  22. # DJANGO CHANNELS
  23. CHANNEL_LAYERS = {
  24. 'default': {
  25. 'BACKEND': 'channels_redis.core.RedisChannelLayer',
  26. 'CONFIG': {
  27. "hosts": [{
  28. 'address': f'redis://{REDIS_HOST}:{REDIS_PORT}',
  29. 'db': REDIS_DB,
  30. 'password': REDIS_PASSWORD,
  31. }],
  32. },
  33. },
  34. }
展开查看全部

相关问题