Flask API使用curl请求触发TypeError,json.loads解析失败
问题现象
触发错误:TypeError: the JSON object must be str, bytes or bytearray, not 'dict',Flask接口代码如下:
@app.route('/getMyData', methods=['GET']) def getMyData(): data = json.loads(request.get_json()) # 错误发生在此行
两种请求方式的差异:
- Python脚本请求无异常:
PARAMS = {"files": ["file1", "file2", "file3", "file4"], "date": [["2000-06-01", "2001-08-01"], ["2005-11-01", "2006-01-01"]], "data": ["data1", "data2", "data3"]} PARAMS_JSON = json.dumps(PARAMS) # 字典转JSON字符串 r = requests.get(url=URL, json=PARAMS_JSON)
- curl请求触发错误:
curl http://127.0.0.1:5000/getMyData -X GET -d '{"files": ["file1", "file2", "file3", "file4"], "date": [["2000-06-01", "2001-08-01"], ["2005-11-01", "2006-01-01"]], "data": ["data1", "data2", "data3"]}' -H 'Content-Type:application/json'
排查发现:Python脚本请求时,request.get_json()返回带双引号的JSON格式字符串;curl请求时,request.get_json()返回Python字典,导致json.loads()无法解析。
原因解析
Flask的
request.get_json()本质:当请求头Content-Type为application/json时,该方法会自动解析请求体中的JSON数据,直接返回对应的Python字典(或其他JSON兼容对象),不需要再用json.loads()二次解析。Python脚本请求的巧合:
requests.get的json参数设计用来接收Python对象(比如字典),它会自动将对象序列化为JSON字符串发送。但你错误地传入了已经序列化好的JSON字符串PARAMS_JSON,此时requests会把这个字符串再次序列化为JSON(相当于发送了一个"JSON格式的字符串")。Flask解析后得到的就是这个原始字符串,所以json.loads()能正常解析——这是错误写法导致的巧合正常。curl请求的正确性:
curl请求是标准的JSON请求:直接发送JSON对象,且设置了正确的Content-Type:application/json。Flask正确解析为Python字典,此时调用json.loads()传入字典,自然触发TypeError。
修正方案
修改Flask接口代码,直接使用request.get_json()的返回结果:
@app.route('/getMyData', methods=['GET']) def getMyData(): data = request.get_json() # 直接获取解析后的字典 # 后续处理data即可
同时修正Python脚本的请求写法,直接传字典给json参数:
PARAMS = {"files": ["file1", "file2", "file3", "file4"], "date": [["2000-06-01", "2001-08-01"], ["2005-11-01", "2006-01-01"]], "data": ["data1", "data2", "data3"]} r = requests.get(url=URL, json=PARAMS) # 直接传字典,requests自动序列化
内容的提问来源于stack exchange,提问作者john stamos

