Redis 笔记:为什么从 Redis 取出的数据是字节而不是字符串?
核心问题 根本原因:Redis 在协议层只认识字节 【读取 - 默认行为】 【读取 - decode_responses=True】 为什么 lpush 时感觉是"放字符串进去"? 一劳永逸的解决方案:decode_responses=True r = redis.Redis( ) 延伸:Set 里的 SHA1 哈希 和 ZSet 也是字节吗? 就像一张纸上写了 "hello":纸上存的是墨水痕迹(物理载体,类比字节),人眼看到的是字母(解读结果,类比字符串)。纸不知道你写的是英文还是中文,Redis 也一样。 为什么 SHA1 哈希"看起来没问题" 总结 Redis 只存字节这句话永远成立。SHA1 哈希"看起来是字符串",只是因为它的字节内容恰好是可读的 ASCII 字符,本质上还是字节。写入时 redis-py 自动编码,读取时默认不解码——用 decode_responses=True 可一劳永逸解决。
通过 lpush 把 URL 字符串放入 Redis,取出来时却是 bytes,需要手动 .decode('utf-8') 才能变回字符串。Redis 把字符串变成字节了吗?
Redis 在协议层面(RESP 协议)只存字节(bytes),不存在"字符串类型"这个概念。
【写入】
Python str "https://example.com"→ redis-py 自动 encode → bytes b"https://example.com"
→ 存入 Redis(Redis 只认 bytes)
Redis 返回 bytes b"https://example.com"→ redis-py 原样返回 bytes
→ 需要手动 .decode('utf-8') → str
Redis 返回 bytes b"https://example.com"→ redis-py 自动 decode → str "https://example.com"
→ 直接用 ✅
因为 redis-py 客户端在写入时帮你自动编码(str → bytes),所以写入时感觉很自然。但取出时默认不做反向解码,原样返回 bytes。
这是 redis-py 的刻意设计:Redis 可以存任意二进制数据(图片、protobuf、序列化对象…),如果客户端自作主张解码,遇到非 UTF-8 的二进制数据就会直接崩溃。所以态度是:"我不知道你存的是什么,原样还给你,你自己决定怎么处理"。
pythonimport redishost='localhost',
port=6379,
decode_responses=True # ← 加这个,所有返回值自动解码为 str
是的,Redis 里所有数据本质都是字节,SHA1 哈希"看起来是字符串"只是因为它的内容恰好是可读的 ASCII 字符。
类比理解
SHA1 的十六进制表示只包含 0-9 a-f,全是 ASCII 字符,ASCII 与 UTF-8 完全一致,所以字节和字符串之间转换透明无损,感觉"就是字符串"。但如果存的是图片二进制数据,decode 就会直接报错,这才暴露了 Redis 底层只存字节的本质。
各数据类型对照表
数据你感知到的Redis 实际存的URL 字符串strbytes(UTF-8 编码)SHA1 哈希值(dupfilter Set)40位十六进制 strbytes(ASCII 编码,恰好可读)ZSet member(request)strbytesZSet scorefloat64位浮点字节