Flutter中JSON解析失败:控制台输出格式异常求助
Flutter解析JSON报错:Expected a value of type 'String', but got one of type '_JsonMap'
问题场景
使用Flutter的Dio库请求Express本地服务器的JSON数据,浏览器能正常获取格式正确的响应,但Flutter控制台抛出类型不匹配错误,无法完成JSON解析。
报错信息
Error: Expected a value of type 'String', but got one of type '_JsonMap' C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:49 throw_ C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 99:3 castError C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 485:10 cast C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 719:17 as packages/task_manager/services/dio_client.dart 12:21 fetchTasks C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 45:50 <fn> C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1660:54 runUnary C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 147:18 handleValue C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 767:44 handleValueCallback C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 796:13 _propagateToListeners C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 558:7 [_complete] C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 47:12 complete C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future.dart 613:44 onValue C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1660:54 runUnary C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 147:18 handleValue C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 767:44 handleValueCallback C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 796:13 _propagateToListeners C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 567:5 [_completeWithValue] C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 640:7 callback C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/schedule_microtask.dart 40:11 _microtaskLoop C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/schedule_microtask.dart 49:5 _startMicrotaskLoop C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 166:15 <fn>
原因分析
Dio默认会自动将JSON格式的响应解析为Map<String, dynamic>,但你的模型转换函数tasksFromJson期望接收原始JSON字符串,再调用json.decode解析,两者类型不匹配导致报错。
解决方案
方案1:直接使用Dio已解析的Map
跳过手动字符串解码步骤,直接将Dio返回的解析好的Map传入模型的fromJson方法:
import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:task_manager/constants/constants.dart'; import 'package:task_manager/models/tasks_model.dart'; class DioClient { final Dio dio = Dio(); Future fetchTasks() async { try{ final response = await dio.get(baseURL+"/tasks"); // 直接使用已解析的Map,无需调用tasksFromJson final tasks = Tasks.fromJson(response.data); debugPrint("${response.data}"); } on DioError catch(e){ debugPrint("StatusCode: ${e.toString()}"); throw Exception("Failed to load Tasks"); } } }
如果不需要字符串与JSON的双向转换,可以简化模型代码:
import 'dart:convert'; // 可删除以下两个函数 // Tasks tasksFromJson(String str) => Tasks.fromJson(json.decode(str)); // String tasksToJson(Tasks data) => json.encode(data.toJson()); class Tasks { Tasks({ required this.tasks, }); List<Task> tasks; factory Tasks.fromJson(Map<String, dynamic> json) => Tasks( tasks: List<Task>.from(json["tasks"].map((x) => Task.fromJson(x))), ); Map<String, dynamic> toJson() => { "tasks": List<dynamic>.from(tasks.map((x) => x.toJson())), }; } class Task { Task({ required this.completed, required this.id, required this.name, required this.v, }); bool completed; String id; String name; int v; factory Task.fromJson(Map<String, dynamic> json) => Task( completed: json["completed"], id: json["_id"], name: json["name"], v: json["__v"], ); Map<String, dynamic> toJson() => { "completed": completed, "_id": id, "name": name, "__v": v, }; }
方案2:让Dio返回原始字符串,手动解析
设置请求的responseType为ResponseType.plain,让Dio返回未解析的原始JSON字符串,再用原有代码解析:
import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:task_manager/constants/constants.dart'; import 'package:task_manager/models/tasks_model.dart'; class DioClient { final Dio dio = Dio(); Future fetchTasks() async { try{ final response = await dio.get( baseURL+"/tasks", options: Options( responseType: ResponseType.plain, ) ); final tasks = tasksFromJson(response.data); debugPrint("${response.data}"); } on DioError catch(e){ debugPrint("StatusCode: ${e.toString()}"); throw Exception("Failed to load Tasks"); } } }
内容的提问来源于stack exchange,提问作者Shanmukha
相关产品推荐
相关产品推荐

