json.dumps() 报 bytes 不可序列化是因为 json 只支持 str、int、float、list、dict、bool 和 none;bytes 必须手动转为 hex() 或 base64 字符串,嵌套结构需递归处理或用 safe default 函数。

为什么 json.dumps() 会报 bytes 不可序列化?
因为 json 模块只认 Python 原生类型:str、int、float、list、dict、bool 和 None。bytes 不在其中,哪怕它只是个二进制字符串(比如从 hashlib.sha256().digest() 或 os.urandom(16) 生成),直接传给 json.dumps() 就会触发这个 TypeError。
最常用且安全的解决方式:预处理 bytes 字段
别指望 json 自动转换,得手动转成 JSON 可接受的表示形式。最通用的做法是用 .decode('utf-8')(仅当 bytes 确实是 UTF-8 编码文本)或更稳妥的 .hex() / base64.b64encode(...).decode('ascii'):
- 如果
bytes是文本(如 API 返回的原始响应体),先尝试my_bytes.decode('utf-8');失败就说明不是文本,别硬 decode - 如果
bytes是任意二进制数据(哈希值、密钥、加密结果),一律用my_bytes.hex()(输出小写十六进制字符串)或base64.b64encode(my_bytes).decode('ascii') - 不要用
str(my_bytes)—— 它会输出类似b'\x01\x02'的 repr 字符串,不是你想要的原始内容
遇到嵌套结构(如 dict/list 含 bytes)怎么办?
不能只改顶层变量,得递归处理。写个简单转换函数比每次手动调用更可靠:
def json_safe(obj):
if isinstance(obj, bytes):
return obj.hex() # 或 base64.b64encode(obj).decode('ascii')
elif isinstance(obj, dict):
return {k: json_safe(v) for k, v in obj.items()}
elif isinstance(obj, list):
return [json_safe(v) for v in obj]
else:
return obj
<h1>使用</h1><p>data = {'key': b'', 'nested': {'id': b'abc'}}
json.dumps(json_safe(data)) # ✅ 正常输出</p>
注意:这个函数不处理 tuple、set 等非标准 JSON 类型,如有需要得额外分支判断。
能否用自定义 default 参数一劳永逸?
可以,但要小心副作用。传给 json.dumps(..., default=...) 的函数会在每个无法序列化的对象上调用:
json.dumps(data, default=lambda x: x.hex() if isinstance(x, bytes) else None)
问题在于:default 函数返回 None 时,json 仍会报错(因为 None 不是“可序列化”,而是没提供有效替代)。必须确保所有分支都返回 JSON 兼容类型:
- 返回
x.hex()✅ - 返回
base64.b64encode(x).decode('ascii')✅ - 返回
None❌(除非你确定该字段允许为空且前端能处理) - 抛异常或返回字符串描述(如
f"<bytes>"</bytes>)——仅用于调试,别用于生产
真正容易被忽略的是:有些库(如 requests.Response.content)返回的就是 bytes,而你可能根本没意识到它藏在深层字典里。检查数据结构比硬套方案更重要。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











