Flask测试中Dict/JSON负载问题:字节类型无法JSON序列化
先拆解你的问题核心:
- 实际通过Swagger/Postman调用端点时功能正常,但单元测试用
json=info发起请求时,触发TypeError: Object of type bytes is not JSON serializable错误; - 改用
data=info时,request.data又变成空字节串。
问题根源分析
json=info请求的问题:
当你用Flask测试客户端的json参数传数据时,Flask会自动把info字典序列化为JSON字符串,同时设置请求头Content-Type: application/json。此时request.data是这个JSON字符串的字节形式(也就是你看到的带b'前缀的数据)。
你的端点代码把这个字节数据存入Redis后,返回时如果直接返回Redis取出的字节值,Flask会尝试将其序列化为JSON响应——但字节类型本身不支持JSON序列化,所以抛出错误。
而Postman/Swagger请求时,要么你隐式处理了返回值,要么端点返回的是其他可序列化内容,所以没触发报错。data=info请求的问题:
测试客户端的data参数只接受字节或字符串类型,如果你直接传字典info,它会被转换成原生字符串表示(比如"{'key': 'value'}"),而且不会自动设置Content-Type为application/json。此时Flask无法正确识别请求体格式,导致request.data为空。
针对性解决方案
方案1:调整端点代码,确保返回内容可JSON序列化
既然你存的是request.data(字节),取出后需要先转换为可序列化的类型再返回:
from flask import json from flask_restx import Resource @api.route('/trayinfo/') class TrayInfo(Resource): def put(self): # 存储请求字节数据到Redis db.set('tray_info', request.data) # 取出数据并转换为JSON对象(如果存的是JSON字节) stored_data = db.get('tray_info') # 处理空值情况,同时把字节转成JSON对象 response_data = json.loads(stored_data) if stored_data else {} return response_data, 200
如果你的场景不需要返回存储的数据,直接返回成功状态即可:
return {"status": "success", "message": "Data stored successfully"}, 200
方案2:调整测试请求的发送方式
方式A:继续用json=info,但端点优先解析JSON
如果希望存的是JSON对象而非原始字节,可以在端点里用request.get_json()解析请求体,再序列化为字符串存入Redis:
def put(self): # 获取解析后的JSON字典 payload = request.get_json() # 序列化为字符串存入Redis(也可以用pickle,但JSON更通用) db.set('tray_info', json.dumps(payload)) # 返回原始payload,天然可序列化 return payload, 200
测试代码保持app.test_client().put('/trayinfo/', json=info)即可,此时不会出现字节序列化问题。
方式B:用data参数发送请求,手动设置Content-Type
如果你必须用data参数,需要先把info序列化为JSON字符串,并指定请求头:
import json # 测试代码里的请求写法 response = app.test_client().put( '/trayinfo/', data=json.dumps(info), content_type='application/json' )
这样request.data会是正确的JSON字节,和Postman发送的请求完全一致,同时端点返回时做好序列化处理即可。
额外调试小技巧
- 测试时可以打印
request.headers确认Content-Type是否正确; - 打印
request.get_data(as_text=True)查看请求体的字符串形式,确认数据是否正确传递。
内容的提问来源于stack exchange,提问作者Jonathan Tuzman

