Flutter Bloc状态异常:200状态码下删除账号未触发ErrorState
问题描述
在Flutter中使用Bloc实现登录功能时遇到以下问题:输入关联已删除账号的手机号时,Bloc无法切换至ErrorState。原因是接口始终返回200状态码,但两种场景的响应结构存在差异:
接口响应示例
- 正常账号响应:
{"status": true,"msg": "Done","data": {"name": "","phone": "","email": "","status": "","address": "","address_short": "","address_link": "","api_token": "","otp": 2379}}
- 已删除账号响应:
{"status": false,"msg": "deleted account"}
相关代码片段
Bloc代码
AuthBloc({required this.auth, required this.sendOTP}) : super(AuthInitial()) { on<AuthEvent>((event, emit) async { if (event is LoginOrRegisterEvent) { emit(LoadingState()); final loginOrRegister = await auth.call( phone: event.phone, name: event.phone, ); loginOrRegister.fold( (failure) { emit(ErrorAuthState(message: AppFunctions.mapFailureToMessage(failure: failure))); }, (auth) { emit(LoadedAuthState(authEntity: auth)); }, ); } }); }
远程数据源代码(Clean Architecture)
class AuthRemoteDataSourceImpl implements AuthRemoteDataSource { @override Future<AuthModel> auth({ required String phone, required String name, String? fcmToken, }) async { final response = await DioHelper.postData( url: ApiConstants.login, data: { 'phone': phone, 'name': name, 'fcmToken': fcmToken ?? '', }, headers: {}, ); if (response!.statusCode == 200) { final authModel = AuthModel.fromJson(response.data); if (kDebugMode) { print('--------------- user Token --------------------'); print(authModel.token); print('------------------------------------------------'); } return authModel; } else { throw ServerException(); } }}
Auth仓库代码
class AuthRepositoryImpl implements AuthRepository { final AuthRemoteDataSource authRemoteDataSource; final NetworkInfo networkInfo; AuthRepositoryImpl({required this.authRemoteDataSource, required this.networkInfo}); @override Future<Either<Failure, AuthEntity>> auth({ required String phone, required String name, String? fcmToken, }) async { if (await networkInfo.isConnected) { try { final remoteProfile = await authRemoteDataSource.auth( phone: phone, name: name, fcmToken: fcmToken ?? '', ); return Right(remoteProfile); } on ServerException { return Left(ServerFailure()); } catch (error) { return Left(ServerFailure()); } } else { return Left(NoInternetConnectionFailure()); } } }
解决方案
问题核心:代码仅判断HTTP状态码为200就直接解析模型,忽略了接口返回的业务状态status: false的情况,导致异常无法触发,Bloc无法进入错误状态。
步骤1:修改远程数据源,校验业务状态
在AuthRemoteDataSourceImpl的auth方法中,先检查响应的业务状态,再决定解析或抛出异常:
class AuthRemoteDataSourceImpl implements AuthRemoteDataSource { @override Future<AuthModel> auth({ required String phone, required String name, String? fcmToken, }) async { final response = await DioHelper.postData( url: ApiConstants.login, data: { 'phone': phone, 'name': name, 'fcmToken': fcmToken ?? '', }, headers: {}, ); if (response!.statusCode == 200) { final responseData = response.data; // 先校验业务状态 if (!responseData['status']) { throw ServerException(message: responseData['msg'] ?? '账号异常'); } // 业务状态正常再解析模型 final authModel = AuthModel.fromJson(responseData); if (kDebugMode) { print('--------------- user Token --------------------'); print(authModel.token); print('------------------------------------------------'); } return authModel; } else { throw ServerException(); } }}
步骤2:更新ServerException,支持携带错误信息
让异常类可以传递具体错误消息:
class ServerException implements Exception { final String? message; ServerException({this.message}); }
步骤3:修改仓库,传递异常信息到Failure
捕获异常时将消息同步到Failure:
class AuthRepositoryImpl implements AuthRepository { // 其他代码不变 @override Future<Either<Failure, AuthEntity>> auth({ required String phone, required String name, String? fcmToken, }) async { if (await networkInfo.isConnected) { try { final remoteProfile = await authRemoteDataSource.auth( phone: phone, name: name, fcmToken: fcmToken ?? '', ); return Right(remoteProfile); } on ServerException catch (e) { return Left(ServerFailure(message: e.message)); } catch (error) { return Left(ServerFailure(message: '登录失败,请重试')); } } else { return Left(NoInternetConnectionFailure()); } } }
步骤4:更新错误消息映射逻辑
确保AppFunctions.mapFailureToMessage能读取自定义错误消息:
class AppFunctions { static String mapFailureToMessage({required Failure failure}) { if (failure is ServerFailure) { return failure.message ?? '服务器错误'; } else if (failure is NoInternetConnectionFailure) { return '请检查网络连接'; } else { return '未知错误'; } } }
修改完成后,当接口返回status: false时,远程数据源会抛出带错误消息的异常,仓库返回Left(ServerFailure),Bloc会触发ErrorAuthState并显示对应错误信息。
内容的提问来源于stack exchange,提问作者KIRAx2000
相关产品推荐
相关产品推荐

