Flutter调用API时如何正确以JSON格式传递含嵌套结构的请求体数据?
正确传递JSON格式请求体的解决方案
问题根源分析
你现在的问题主要出在两个关键地方:
- 错误嵌套对象转字符串:
weekends和weekdays本应是嵌套的JSON对象,但你用.toString()把它们转成了普通字符串,直接破坏了整个请求体的JSON结构,API收到后根本无法解析这些字段。 - 错误的JSON编码逻辑:
jsonEncode(body.toString())属于双重编码(先把对象转成字符串,再对字符串二次编码),而且MultipartRequest.fields是用来传递键值对表单数据的,直接把整个JSON字符串塞进去会让请求格式完全不符合API预期。
解决方案步骤
1. 修正请求体构造,保留嵌套Map结构
首先要去掉weekends和weekdays后面的.toString(),让它们保持为Map类型,这样整个body就是一个合法的嵌套Map,后续才能正确编码为标准JSON:
// 修正后的请求体构造 dynamic body = { 'doctor_availablity_done': StatusEnum.Yes.index.toString(), 'emergency_call': emergencyCall, 'weekends': { "days": selectedWeekendList.toString(), "time_period": { "morning": { "start_time": weekendMorningStart.value.toString(), "end_time": weekendMorningEnd.value.toString() }, "afternoon": { "start_time": weekendAfternoonStart.value.toString(), "end_time": weekendAfternoonEnd.value.toString() }, "evening": { "start_time": weekendEveningStart.value.toString(), "end_time": weekendEveningEnd.value.toString() }, "night": { "start_time": weekendNightStart.value.toString(), "end_time": weekendNightStart.value.toString() } } }, // 去掉.toString(),保留Map结构 'weekdays': { "days": selectedWeekdaysList.toString(), "time_period": { "morning": { "start_time": weekdaysMorningStart.value.toString(), "end_time": weekdaysMorningEnd.value.toString() }, "afternoon": { "start_time": weekdaysAfternoonStart.value.toString(), "end_time": weekdaysAfternoonEnd.value.toString() }, "evening": { "start_time": weekdaysEveningStart.value.toString(), "end_time": weekdaysEveningEnd.value.toString() }, "night": { "start_time": weekdaysNightStart.value.toString(), "end_time": weekdaysNightStart.value.toString() } } }, // 去掉.toString(),保留Map结构 };
2. 选择正确的请求方式
根据你是否需要上传文件,分两种场景处理:
场景A:不需要上传文件(普通JSON请求)
如果只是传递JSON数据,不需要附带文件,直接使用http.post是最简洁的方案:
var headers = { 'Authorization': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvdG90YWxoZWFsdGhzb2x1dGlvbnMub3JnLmluXC9tZWRpY2FsLWRldlwvYXBpXC9kb2N0b3JcL2xvZ2luIiwiaWF0IjoxNjYwMDQyMzg3LCJleHAiOjE2NjAxMjg3ODcsIm5iZiI6MTY2MDA0MjM4NywianRpIjoiMzI2Y2xsNzEybElYaktqSyIsInN1YiI6MTYzLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.5FbSnY-tPQMdyNFxdWmPuxCmQAPUcutejWkKPJT3XTE', 'Content-Type': 'application/json' // 必须添加这个头部,告知API接收的是JSON格式 }; http.Response response = await http.post( Uri.parse(url), headers: headers, body: jsonEncode(body), // 直接对合法的嵌套Map进行JSON编码 ); if (response.statusCode == 200) { print(response.body); } else { print(response.reasonPhrase); }
场景B:需要上传文件(必须用MultipartRequest)
如果你确实需要用MultipartRequest(比如要同时上传文件和JSON数据),需要把JSON数据作为一个表单字段添加进去:
var headers = { 'Authorization': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvdG90YWxoZWFsdGhzb2x1dGlvbnMub3JnLmluXC9tZWRpY2FsLWRldlwvYXBpXC9kb2N0b3JcL2xvZ2luIiwiaWF0IjoxNjYwMDQyMzg3LCJleHAiOjE2NjAxMjg3ODcsIm5iZiI6MTY2MDA0MjM4NywianRpIjoiMzI2Y2xsNzEybElYaktqSyIsInN1YiI6MTYzLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.5FbSnY-tPQMdyNFxdWmPuxCmQAPUcutejWkKPJT3XTE' }; var request = http.MultipartRequest( 'POST', Uri.parse(url) ); // 将JSON数据作为一个表单字段添加 request.fields['data'] = jsonEncode(body); // 如果需要上传文件,在这里添加:request.files.add(await http.MultipartFile.fromPath('file', '你的文件路径')); request.headers.addAll(headers); http.StreamedResponse response = await request.send(); if (response.statusCode == 200) { print(await response.stream.bytesToString()); } else { print(response.reasonPhrase); }
注意:这种方式需要API端支持从表单字段读取JSON数据,如果API要求整个请求体是纯JSON,那还是用场景A的方案更合适。
内容的提问来源于stack exchange,提问作者Vrusti Patel
相关产品推荐
相关产品推荐

