Flutter解析含Null的登录JSON遇类型异常,求空值处理方案
登录响应JSON解析问题修复
问题概述
在解析登录接口的JSON响应时,遇到两个核心问题:
- 登录失败(用户名/密码无效)时,
userData字段为null,但模型类未处理空值,引发解析异常 - 抛出类型转换异常:
type '_Map<String, dynamic>' is not a subtype of type 'ErrorDetails'
响应示例
- 用户名无效时的响应:
{ "userData": null, "verificationStatus": false, "errorDetails": [ { "errorMap": { "Username": "The Username Is Invalid" } } ], "siteUserHBList": null }
- 密码无效时的响应:
{ "userData": null, "verificationStatus": false, "errorDetails": [ { "errorMap": { "Password": "The Password Is Invalid" } } ], "siteUserHBList": null }
当前模型与解析代码
模型类及解析逻辑如下:
import 'dart:convert'; class LoginResponse { final UserData userData; final bool verificationStatus; final List<ErrorDetails> errorDetails; LoginResponse({required this.userData, required this.verificationStatus, required this.errorDetails}); factory LoginResponse.fromJson(Map<String, dynamic> json) { return LoginResponse( verificationStatus: json['verificationStatus'] as bool, userData: UserData.fromJson(json['userData']) , errorDetails: List<ErrorDetails>.from(json["errorDetails"].map((x) => ErrorDetails.fromJson(x))), ); } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['userData'] = this.userData; data['verificationStatus'] = this.verificationStatus; data['errorDetails'] = List<dynamic>.from(errorDetails.map((x) => x.toJson())); return data; } } class ErrorDetails { final ErrorMap errorMap; ErrorDetails({required this.errorMap }); factory ErrorDetails.fromJson(Map<String, dynamic> json) { return ErrorDetails( errorMap: ErrorMap.fromJson(json['errorMap']) ); } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['errorMap'] = this.errorMap; return data; } } class ErrorMap { final String? Username; // nullable final String? Password; // nullable ErrorMap({this.Username, this.Password}); factory ErrorMap.fromJson(Map<String, dynamic> json) { return ErrorMap ( Username: json['Username'] as String?, Password: json['Password'] as String?, ); } Map<String, dynamic> toJson() { final Map<String, dynamic> data = <String, dynamic>{}; data['Username'] = Username; data['Password'] = Password; return data; } } class UserData{ final int userId; final int applicationId; final int siteId; final String username; final String email; final String firstName; final String lastName; final String profileImageUrl; UserData({required this.userId, required this.applicationId, required this.siteId, required this.username, required this.email, required this.firstName, required this.lastName, required this.profileImageUrl}); factory UserData.fromJson(Map<String, dynamic> json) { return UserData( userId: json['userId'] as int, applicationId: json['applicationId'] as int, siteId: json['siteId'] as int, username: json['username'] as String, email: json['email'] as String, firstName: json['firstName'] as String, lastName: json['lastName'] as String, profileImageUrl: json['profileImageUrl'] as String, ); } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['userId'] = this.userId; data['applicationId'] = this.applicationId; data['siteId'] = this.siteId; data['username'] = this.username; data['email'] = this.email; data['firstName'] = this.firstName; data['lastName'] = this.lastName; data['profileImageUrl'] = this.profileImageUrl; return data; } }
解析代码:
Map<String, dynamic> parsedData = jsonDecode(response.body); LoginResponse loginResponse = LoginResponse.fromJson(parsedData); print('errormap:>>$loginResponse.errorDetails[0].errorMap.Username');
抛出的异常
type '_Map<String, dynamic>' is not a subtype of type 'ErrorDetails'
问题原因分析
- userData空值未处理:登录失败时
userData为null,但LoginResponse中userData被定义为非空类型,且fromJson直接调用UserData.fromJson(json['userData']),此时null无法转为Map<String, dynamic>,触发的异常会干扰后续解析逻辑,导致错误提示指向ErrorDetails。 - errorDetails空值与格式兼容问题:若登录成功时后端返回
errorDetails为null,当前解析逻辑会因null无法调用map方法报错;若后端偶尔返回单个ErrorDetails对象而非数组,也会触发类型转换异常。
修复方案
1. 处理userData的空值
修改LoginResponse类,将userData改为可空类型,并在解析时添加空值判断:
class LoginResponse { final UserData? userData; // 改为可空类型 final bool verificationStatus; final List<ErrorDetails>? errorDetails; // 同时处理errorDetails的空值 LoginResponse({this.userData, required this.verificationStatus, this.errorDetails}); factory LoginResponse.fromJson(Map<String, dynamic> json) { return LoginResponse( verificationStatus: json['verificationStatus'] as bool, // 仅当userData不为null时解析 userData: json['userData'] != null ? UserData.fromJson(json['userData']) : null, // 处理errorDetails的空值与格式兼容 errorDetails: json["errorDetails"] != null ? (json["errorDetails"] is List ? List<ErrorDetails>.from(json["errorDetails"].map((x) => ErrorDetails.fromJson(x))) : [ErrorDetails.fromJson(json["errorDetails"])]) // 单个对象转为数组 : [], // 或根据需求改为null ); } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['userData'] = this.userData?.toJson(); // 可空类型调用方法需加? data['verificationStatus'] = this.verificationStatus; data['errorDetails'] = errorDetails?.map((x) => x.toJson()).toList(); return data; } }
2. 优化错误信息读取逻辑
在main.dart中读取错误信息时,添加空值判断避免索引越界:
Map<String, dynamic> parsedData = jsonDecode(response.body); LoginResponse loginResponse = LoginResponse.fromJson(parsedData); if (loginResponse.errorDetails != null && loginResponse.errorDetails!.isNotEmpty) { var errorMap = loginResponse.errorDetails![0].errorMap; if (errorMap.Username != null) { print('用户名错误: ${errorMap.Username}'); } else if (errorMap.Password != null) { print('密码错误: ${errorMap.Password}'); } }
内容的提问来源于stack exchange,提问作者Sreejith Sree
相关产品推荐
相关产品推荐

