You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 17:33:14