Flutter+Chopper请求报错:_Map<String,dynamic>非Auth?子类型
问题:POST请求返回200,但拦截器抛出TypeError异常(仅成功请求触发)
发起POST请求时,服务器返回200状态码,但拦截器抛出TypeError异常。仅成功请求会出现该问题,失败请求可正常返回Object?,需排查问题。
Chopper Client
class ClientName { @pragma('Singleton') ClientName._(); static final instance = ClientName._(); @pragma('Client') final ChopperClient client = ChopperClient( converter: const JsonConverter(), errorConverter: const JsonConverter(), baseUrl: Uri(scheme: 'https', host: 'redacted'), services: [AuthService.create()]); @pragma('Services') AuthService get auth => client.getService<AuthService>(); }
Auth Service
// 生成器运行必需代码 part "auth_service.chopper.dart"; @ChopperApi() abstract class AuthService extends ChopperService { static AuthService create([ChopperClient? client]) => _$AuthService(client); @Post(path: "/v1/oauth/token", headers: {"Accept": "application/json"}) Future<Response<Auth>> login(@Body() Map<String, dynamic> data); }
Auth Model
class Auth { Auth( this.status, this.currentTime, this.accessToken, this.tokenType, this.userId, this.expiresAt, this.createdAt, ); final String status; final String currentTime; final String accessToken; final String tokenType; final int userId; final String expiresAt; final String createdAt; Auth copyWith({ String? status, String? currentTime, String? accessToken, String? tokenType, int? userId, String? expiresAt, String? createdAt, }) { return Auth( status ?? this.status, currentTime ?? this.currentTime, accessToken ?? this.accessToken, tokenType ?? this.tokenType, userId ?? this.userId, expiresAt ?? this.expiresAt, createdAt ?? this.createdAt, ); } Map<String, dynamic> toMap() { return <String, dynamic>{ 'status': status, 'currentTime': currentTime, 'accessToken': accessToken, 'tokenType': tokenType, 'userId': userId, 'expiresAt': expiresAt, 'createdAt': createdAt, }; } factory Auth.fromMap(Map<String, dynamic> map) { return Auth( map['status'] as String, map['currentTime'] as String, map['accessToken'] as String, map['tokenType'] as String, map['userId'] as int, map['expiresAt'] as String, map['createdAt'] as String, ); } String toJson() => json.encode(toMap()); factory Auth.fromJson(String source) => Auth.fromMap(json.decode(source) as Map<String, dynamic>); @override String toString() { return 'Auth(status: $status, currentTime: $currentTime, accessToken: $accessToken, tokenType: $tokenType, userId: $userId, expiresAt: $expiresAt, createdAt: $createdAt)'; } @override bool operator ==(covariant Auth other) { if (identical(this, other)) return true; return other.status == status && other.currentTime == currentTime && other.accessToken == accessToken && other.tokenType == tokenType && other.userId == userId && other.expiresAt == expiresAt && other.createdAt == createdAt; } @override int get hashCode { return status.hashCode ^ currentTime.hashCode ^ accessToken.hashCode ^ tokenType.hashCode ^ userId.hashCode ^ expiresAt.hashCode ^ createdAt.hashCode; } }
请求代码
class LoginRepository extends Repository { Future<Response<Auth>> login(String username, String password) async { return ClientName.instance.auth.login(AuthRequest(grantType: "password", username: username, password: password).toMap()); } }
排查与解决方法
- 自定义Converter处理模型解析
默认JsonConverter无法自动识别Auth类的fromMap方法,需自定义转换器完成JSON到模型的映射:
class CustomJsonConverter extends JsonConverter { @override Response<ResultType> convertResponse<ResultType, Item>(Response response) { final baseResponse = super.convertResponse(response); if (ResultType == Auth) { return Response( body: Auth.fromMap(baseResponse.body) as ResultType, statusCode: baseResponse.statusCode, headers: baseResponse.headers, error: baseResponse.error, ); } return baseResponse; } }
替换ChopperClient中的converter: const JsonConverter()为converter: CustomJsonConverter()。
- 修复响应字段不匹配与强制转换风险
检查服务器返回的JSON字段名、类型是否与Auth类完全一致(注意大小写)。同时避免强制转换导致崩溃,修改fromMap方法添加空安全兜底:
factory Auth.fromMap(Map<String, dynamic> map) { return Auth( map['status'] as String? ?? '', map['currentTime'] as String? ?? '', map['accessToken'] as String? ?? '', map['tokenType'] as String? ?? '', map['userId'] as int? ?? 0, map['expiresAt'] as String? ?? '', map['createdAt'] as String? ?? '', ); }
- 重新生成Chopper代码
确保生成的auth_service.chopper.dart文件正确,执行以下命令重新生成:
dart run build_runner build
内容的提问来源于stack exchange,提问作者Brandon Stillitano
相关产品推荐
相关产品推荐

