139 lines
4.9 KiB
Python
139 lines
4.9 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""修复 Redis URL 解析问题"""
|
|||
|
|
|
|||
|
|
config_path = "/app/app/config.py"
|
|||
|
|
|
|||
|
|
with open(config_path, "r", encoding="utf-8") as f:
|
|||
|
|
content = f.read()
|
|||
|
|
|
|||
|
|
# 找到并替换 create_redis_client 方法
|
|||
|
|
old = ''' def create_redis_client(self) -> aioredis.Redis:
|
|||
|
|
"""创建 Redis 异步客户端实例。
|
|||
|
|
|
|||
|
|
使用单独的 host/port/password 参数,避免 URL 解析问题
|
|||
|
|
(特别是密码中包含特殊字符 ! @ # 时)。
|
|||
|
|
|
|||
|
|
自动附加 protocol=2 参数,强制使用 RESP2 协议。
|
|||
|
|
原因:Windows 版 Redis 3.x 不支持 RESP3 协议(HELLO 命令),
|
|||
|
|
而 redis-py 8.0+ 默认使用 RESP3,会导致连接失败。
|
|||
|
|
全项目统一使用此方法创建 Redis 客户端,避免协议不匹配。
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
aioredis.Redis: 配置好的 Redis 异步客户端
|
|||
|
|
"""
|
|||
|
|
# 如果 redis_url 为空,使用默认值
|
|||
|
|
if not self.redis_url:
|
|||
|
|
# 默认值:本地 Redis
|
|||
|
|
return aioredis.Redis(
|
|||
|
|
host="localhost",
|
|||
|
|
port=6379,
|
|||
|
|
protocol=2,
|
|||
|
|
decode_responses=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 解析 REDIS_URL 提取连接参数
|
|||
|
|
# 格式: redis://:password@host:port/db
|
|||
|
|
from urllib.parse import urlparse
|
|||
|
|
parsed = urlparse(self.redis_url)
|
|||
|
|
|
|||
|
|
# 提取密码(去掉用户名部分,如果存在的话)
|
|||
|
|
password = parsed.password
|
|||
|
|
if not password:
|
|||
|
|
# 尝试从 netloc 中提取(格式 :password@host)
|
|||
|
|
netloc = parsed.netloc
|
|||
|
|
if "@" in netloc:
|
|||
|
|
password = netloc.split("@")[0].split(":")[-1]
|
|||
|
|
|
|||
|
|
return aioredis.Redis(
|
|||
|
|
host=parsed.hostname or "localhost",
|
|||
|
|
port=parsed.port or 6379,
|
|||
|
|
password=password,
|
|||
|
|
db=parsed.path and int(parsed.path.lstrip("/")) or 0,
|
|||
|
|
protocol=2,
|
|||
|
|
decode_responses=True
|
|||
|
|
)'''
|
|||
|
|
|
|||
|
|
new = ''' def create_redis_client(self) -> aioredis.Redis:
|
|||
|
|
"""创建 Redis 异步客户端实例。
|
|||
|
|
|
|||
|
|
使用单独的 host/port/password 参数,避免 URL 解析问题
|
|||
|
|
(特别是密码中包含特殊字符 ! @ # 时)。
|
|||
|
|
|
|||
|
|
自动附加 protocol=2 参数,强制使用 RESP2 协议。
|
|||
|
|
原因:Windows 版 Redis 3.x 不支持 RESP3 协议(HELLO 命令),
|
|||
|
|
而 redis-py 8.0+ 默认使用 RESP3,会导致连接失败。
|
|||
|
|
全项目统一使用此方法创建 Redis 客户端,避免协议不匹配。
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
aioredis.Redis: 配置好的 Redis 异步客户端
|
|||
|
|
"""
|
|||
|
|
# 如果 redis_url 为空,使用默认值
|
|||
|
|
if not self.redis_url:
|
|||
|
|
# 默认值:本地 Redis
|
|||
|
|
return aioredis.Redis(
|
|||
|
|
host="localhost",
|
|||
|
|
port=6379,
|
|||
|
|
protocol=2,
|
|||
|
|
decode_responses=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 解析 REDIS_URL 提取连接参数
|
|||
|
|
# 格式: redis://:password@host:port/db
|
|||
|
|
# 注意:密码中可能包含 @ 字符,需要特殊处理
|
|||
|
|
# 例如:redis://:R3d!s@2026#Secure@redis:6379/0
|
|||
|
|
# 其中 :R3d!s@2026#Secure 是密码,redis 是主机名
|
|||
|
|
|
|||
|
|
url = self.redis_url
|
|||
|
|
# 找到最后一个 @ 之前的所有内容作为密码
|
|||
|
|
# 格式: redis://:password@host:port/db
|
|||
|
|
scheme_prefix = "redis://:"
|
|||
|
|
if url.startswith(scheme_prefix):
|
|||
|
|
# 提取 @ 之后的部分(主机和端口)
|
|||
|
|
rest = url[len(scheme_prefix):]
|
|||
|
|
at_pos = rest.rfind("@")
|
|||
|
|
if at_pos > 0:
|
|||
|
|
password = rest[:at_pos]
|
|||
|
|
host_part = rest[at_pos+1:]
|
|||
|
|
# 解析主机部分
|
|||
|
|
if "/" in host_part:
|
|||
|
|
host_port, db = host_part.split("/", 1)
|
|||
|
|
db = int(db) if db.isdigit() else 0
|
|||
|
|
else:
|
|||
|
|
host_port = host_part
|
|||
|
|
db = 0
|
|||
|
|
|
|||
|
|
if ":" in host_port:
|
|||
|
|
host, port = host_port.split(":", 1)
|
|||
|
|
port = int(port)
|
|||
|
|
else:
|
|||
|
|
host = host_port
|
|||
|
|
port = 6379
|
|||
|
|
|
|||
|
|
return aioredis.Redis(
|
|||
|
|
host=host,
|
|||
|
|
port=port,
|
|||
|
|
password=password,
|
|||
|
|
db=db,
|
|||
|
|
protocol=2,
|
|||
|
|
decode_responses=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 回退:使用 from_url
|
|||
|
|
return aioredis.from_url(url, protocol=2)'''
|
|||
|
|
|
|||
|
|
if old not in content:
|
|||
|
|
print("ERROR: Could not find old method")
|
|||
|
|
print("Looking for method...")
|
|||
|
|
import re
|
|||
|
|
match = re.search(r'def create_redis_client.*?(?=\n def |\nclass |\Z)', content, re.DOTALL)
|
|||
|
|
if match:
|
|||
|
|
print(f"Found: {match.group(0)[:200]}")
|
|||
|
|
sys.exit(1)
|
|||
|
|
|
|||
|
|
new_content = content.replace(old, new)
|
|||
|
|
|
|||
|
|
with open(config_path, "w", encoding="utf-8") as f:
|
|||
|
|
f.write(new_content)
|
|||
|
|
|
|||
|
|
print("Fixed!")
|