
Redis 的 GET 命令仅适用于字符串类型键,当对 List、Set、Hash、ZSet 等非字符串类型键调用 GET 时会抛出 WRONGTYPE 异常;正确做法是先用 TYPE 命令探测键类型,再选用对应命令(如 LRANGE、SMEMBERS、HGETALL 等)获取数据。
redis 的 `get` 命令仅适用于字符串类型键,当对 list、set、hash、zset 等非字符串类型键调用 `get` 时会抛出 `wrongtype` 异常;正确做法是先用 `type` 命令探测键类型,再选用对应命令(如 `lrange`、`smembers`、`hgetall` 等)获取数据。
在 Redis 中,同一数据库内不同键可存储完全不同的数据结构:字符串(string)、列表(list)、集合(set)、哈希(hash)、有序集合(zset)等。redis.Redis.get() 方法仅设计用于读取字符串类型值,若目标键实际存储的是其他类型(例如你示例中的 asgi:group:348 很可能是一个 List 或 Hash,常见于 Django Channels 等异步框架的组消息队列),直接调用 get() 就会触发 redis.exceptions.ResponseError: WRONGTYPE 错误。
✅ 正确的排查与获取流程如下:
-
先探测键类型:使用
redis.type(key)获取键的底层数据类型(返回字节串,如b'string'、b'list'、b'hash'等); - 根据类型选择对应读取命令;
- 统一处理逻辑,避免硬编码假设。
以下是一个健壮、可复用的 Python 示例:
import redis
pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
r = redis.Redis(connection_pool=pool)
def safe_get_value(r, key):
"""安全获取任意类型 Redis 键的值,返回 Python 可读结构"""
key_bytes = key if isinstance(key, bytes) else key.encode()
key_type = r.type(key_bytes).decode() # 如 'string', 'list', 'hash', 'set', 'zset'
try:
if key_type == 'string':
return r.get(key_bytes)
elif key_type == 'list':
return r.lrange(key_bytes, 0, -1) # 全量获取列表
elif key_type == 'hash':
return r.hgetall(key_bytes) # 返回 {b'field': b'value', ...}
elif key_type == 'set':
return r.smembers(key_bytes)
elif key_type == 'zset':
return r.zrange(key_bytes, 0, -1, withscores=True)
else:
return f"<unsupported type:>"
except Exception as e:
return f"<error:>"
# 使用示例
for key in r.keys("asgi:group:*"): # 推荐加通配符缩小范围,避免全库扫描
value = safe_get_value(r, key)
print(f"Key: {key!r} → Type: {r.type(key).decode()} → Value: {value}")</error:></unsupported>
⚠️ 注意事项:
-
KEYS *在生产环境应禁用(阻塞主线程、性能差),推荐改用SCAN游标式遍历; -
r.type()是 O(1) 操作,开销极小,务必作为访问前必检步骤; - 对于
Hash/ZSet等结构化类型,hgetall()或zrange()可能返回大量数据,需结合业务做分页或字段筛选; - 若确定某类键始终为特定类型(如
asgi:group:*总是 List),可跳过type()检查,直接用lrange(key, 0, -1),但首次调试阶段强烈建议保留类型校验。
总结:Redis 不是“万能 GET”键值库,而是多模型数据结构服务器。尊重其类型语义,通过 TYPE → 分支读取 的范式,即可彻底规避 WRONGTYPE 错误,并构建出稳定、可维护的缓存访问逻辑。











