Flutter Cubit处理400错误未进入指定错误状态反而抛出异常
问题:服务器返回400状态码却未进入
OrderFinishError状态,反而触发StateError异常 页面加载时向服务器发送请求,服务器返回400错误状态,但未进入OrderFinishError状态分支,反而执行了throw StateError('err');。类似逻辑在其他页面可正常运行,这是项目收尾的最后任务。
状态定义
abstract class OrderFinishState {} class OrderFinishNotLoading extends OrderFinishState {} class OrderFinishLoading extends OrderFinishState {} class OrderFinishLoaded extends OrderFinishState { OrderFinishLoaded({required this.orderFinishModels}); final OrderFinishModels orderFinishModels; } class OrderFinishError extends OrderFinishState { OrderFinishError({required this.errorModels}); final ErrorModels errorModels; }
Cubit代码
class OrderFinishCubit extends Cubit<OrderFinishState> { OrderFinishCubit() : super(OrderFinishNotLoading()); Future<void> orderFinish() async { emit(OrderFinishLoading()); final prefs = await SharedPreferences.getInstance(); final token = prefs.getString('token'); final orderId = prefs.getInt('orderId'); final response = await http.post(Uri.parse(ConfigUrl.orderFinish), headers: { "Content-Type": "application/vnd.api+json", "Accept": "application/vnd.api+json", "Authorization": "Bearer $token", }, body: jsonEncode(<String, dynamic>{ "order_id": orderId, })); if (response.statusCode == 200) { log('test order finish cubit'); log(orderId.toString()); final responseJson = json.decode(response.body) as Map<String, dynamic>; log(json.decode(response.body).toString()); emit(OrderFinishLoaded( orderFinishModels: OrderFinishModels.fromJson(responseJson))); } else { final jsonError = json.decode(response.body) as Map<String, dynamic>; log(response.statusCode.toString()); log(json.decode(response.body).toString()); emit(OrderFinishError(errorModels: ErrorModels.fromJson(jsonError))); } } }
BlocBuilder代码
return BlocProvider<OrderFinishCubit>( create: (context) => OrderFinishCubit()..orderFinish(), child: Scaffold( body: BlocBuilder<OrderFinishCubit, OrderFinishState>( builder: (context, state) { if (state is OrderFinishNotLoading) { return Center( child: Text('Дождитесь загрузки или перезапустите приложение'), ); } else if (state is OrderFinishLoading) { return const Center( child: CircularProgressIndicator(), ); } else if (state is OrderFinishLoaded) { return Home(); } else if (state is OrderFinishError) { Scaffold( body: SafeArea( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text(state.errorModels.message), SizedBox( height: 15, ), InkWell( onTap: () async { context.go('/activeTravel'); }, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(32), color: ConfigColor.green, ), width: width, height: 44, child: Center( child: Text('На главную', textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500)), ))), ], ), )); } throw StateError('err'); }, ), ));
问题原因与解决方案
1. 直接原因:OrderFinishError分支缺少return
BlocBuilder的OrderFinishError分支中,创建了Scaffold但没有用return返回,导致代码执行完该分支后继续走到最后的throw StateError('err');语句。
修复代码:
else if (state is OrderFinishError) { // 添加return返回错误页面 return Scaffold( body: SafeArea( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text(state.errorModels.message), SizedBox( height: 15, ), InkWell( onTap: () async { context.go('/activeTravel'); }, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(32), color: ConfigColor.green, ), width: width, height: 44, child: Center( child: Text('На главную', textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500)), ))), ], ), )); }
2. 潜在问题:未处理请求过程中的异常
Cubit的orderFinish方法没有全局异常捕获,以下场景会导致无法发射OrderFinishError状态:
token或orderId为null,导致请求失败- 服务器返回的错误响应体无法解析为JSON
- 网络请求抛出异常(如无网络、超时)
修复代码:
Future<void> orderFinish() async { emit(OrderFinishLoading()); try { final prefs = await SharedPreferences.getInstance(); final token = prefs.getString('token'); final orderId = prefs.getInt('orderId'); // 校验必要参数 if (token == null || orderId == null) { emit(OrderFinishError(errorModels: ErrorModels(message: '缺少必要请求参数'))); return; } final response = await http.post(Uri.parse(ConfigUrl.orderFinish), headers: { "Content-Type": "application/vnd.api+json", "Accept": "application/vnd.api+json", "Authorization": "Bearer $token", }, body: jsonEncode(<String, dynamic>{ "order_id": orderId, })); if (response.statusCode == 200) { log('test order finish cubit'); log(orderId.toString()); final responseJson = json.decode(response.body) as Map<String, dynamic>; log(json.decode(response.body).toString()); emit(OrderFinishLoaded( orderFinishModels: OrderFinishModels.fromJson(responseJson))); } else { Map<String, dynamic> jsonError; try { jsonError = json.decode(response.body) as Map<String, dynamic>; } catch (e) { // 处理JSON解析失败的情况 jsonError = {'message': '服务器返回无效错误信息'}; } log(response.statusCode.toString()); log(jsonError.toString()); emit(OrderFinishError(errorModels: ErrorModels.fromJson(jsonError))); } } catch (e) { // 捕获所有请求异常 log('请求异常: $e'); emit(OrderFinishError(errorModels: ErrorModels(message: '请求失败,请检查网络'))); } }
3. 优化建议:替换throw为默认错误UI
避免因未覆盖的状态导致崩溃,将最后的throw StateError('err');替换为默认错误页面:
// 替换throw语句 return Center( child: Text('未知错误,请重试'), );
内容的提问来源于stack exchange,提问作者Daniil
相关产品推荐
相关产品推荐

