Flutter中Dio报错:'String'无法转为'Map<String, dynamic>'类型
问题分析与解决方案
错误根源
这个报错type 'String' is not a subtype of type 'Map<String, dynamic>' in type cast说白了就是:你把接口返回的字符串数据硬当成Map格式去解析成SurveyDataModel,类型对不上才炸的。常见情况有这几种:
- 接口实际返回的是纯文本(比如"请求成功"、错误提示),不是JSON对象
- 接口返回的JSON格式有问题(比如是数组
[]不是单个对象{},或者语法错误) - Dio请求时没处理好响应格式(比如手动把数据转成了字符串,或者没设置正确的
responseType)
分模块排查修复
1. GetTasksRepo 层:先搞清楚接口返回的是什么
你得先把Dio请求的响应数据打出来看看,别上来就强转类型:
// 错误示范:直接把response.data当Map转 final Map<String, dynamic> data = response.data as Map<String, dynamic>; // 正确操作:先判断类型,再处理 Future<SurveyDataModel> getSurveyById(String surveyId) async { try { final response = await dio.get('/surveys/$surveyId'); // 先打印这俩,看看接口到底返回啥 print('问卷接口返回内容:${response.data}'); print('返回数据类型:${response.data.runtimeType}'); if (response.data is Map<String, dynamic>) { return SurveyDataModel.fromJson(response.data); } else if (response.data is String) { // 如果是字符串,先试试能不能转成JSON try { final jsonData = jsonDecode(response.data) as Map<String, dynamic>; return SurveyDataModel.fromJson(jsonData); } catch (e) { throw Exception('JSON格式错了:$e'); } } else { throw Exception('返回类型不对:${response.data.runtimeType}'); } } catch (e) { throw Exception('Dio请求出问题:$e'); } }
- 重点:先打印确认返回内容和类型,别瞎猜
- 如果接口返回的是JSON数组(比如
[{"id":1}]),那得把解析逻辑改成处理List<Map<String,dynamic>>,还要对应改Model的解析方法
2. SurveyDataModel 层:Model结构要和接口返回对应上
检查你的fromJson方法,字段和接口返回的JSON key得对上:
// 举个例子,你得根据实际接口返回改 class SurveyDataModel { final String id; final String title; final List<QuestionModel> questions; SurveyDataModel({required this.id, required this.title, required this.questions}); factory SurveyDataModel.fromJson(Map<String, dynamic> json) { // 最好给字段加默认值,避免接口返回null炸锅 return SurveyDataModel( id: json['id'] ?? '', title: json['title'] ?? '', questions: (json['questions'] as List?)?.map((q) => QuestionModel.fromJson(q)).toList() ?? [], ); } }
- 要是接口返回的JSON里没有某个key,或者类型和Model字段不匹配,也会触发类型错误
- 加个
??给默认值,能减少不少意外报错
3. SurveyScreen 层:跳转和加载逻辑别出错
跳转的时候要传对问卷ID,页面加载时要捕获错误:
class SurveyScreen extends StatefulWidget { final String surveyId; const SurveyScreen({super.key, required this.surveyId}); @override State<SurveyScreen> createState() => _SurveyScreenState(); } class _SurveyScreenState extends State<SurveyScreen> { SurveyDataModel? _survey; String? _errorMsg; @override void initState() { super.initState(); _loadSurvey(); } Future<void> _loadSurvey() async { try { final survey = await GetTasksRepo().getSurveyById(widget.surveyId); setState(() { _survey = survey; }); } catch (e) { setState(() { _errorMsg = e.toString(); }); } } @override Widget build(BuildContext context) { if (_errorMsg != null) { return Center(child: Text('加载失败:$_errorMsg')); } if (_survey == null) { return const Center(child: CircularProgressIndicator()); } // 渲染问卷内容 return Scaffold( appBar: AppBar(title: Text(_survey!.title)), body: ListView( children: _survey!.questions.map((q) => Text(q.text)).toList(), ), ); } }
- 跳转的时候要确保传的ID正确:比如任务列表里点按钮时
Navigator.push(context, MaterialPageRoute(builder: (_) => SurveyScreen(surveyId: task.surveyId))); - 页面里加错误提示,出问题的时候能直接看到啥原因
额外排查小技巧
- 用Postman或者浏览器直接访问问卷接口,看看返回的内容是不是你预期的JSON对象
- 检查Dio的全局配置,有没有把
responseType改成ResponseType.plain了(默认是JSON,改了就会返回字符串) - 如果返回的是HTML页面(比如404、500错误页),那就是接口地址错了或者后端出问题了,先把接口搞定
内容的提问来源于stack exchange,提问作者KLVN
相关产品推荐
相关产品推荐

