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

Flutter中Dio 5.4.3+1无法捕获错误问题(GetX场景)

解决Flutter GetX+Dio请求错误无法捕获的问题

问题根源

你的代码无法捕获错误的核心原因有两个:

  • await DioService().getMethod(url) 执行在try代码块之外,Dio请求抛出的错误根本没进入捕获逻辑
  • DioService的getMethod仅用then处理成功响应,未处理请求失败的情况,错误会直接向上抛出但上层未包裹捕获

另外错误处理逻辑存在嵌套错误:把connectionError判断放在401的分支里,而连接错误时e.response为null,永远不会触发这个提示。

修复步骤

1. 调整请求调用位置,包裹完整请求流程到try块

将Dio请求的调用移到try内部,确保所有请求相关的错误都能被捕获。

2. 优化DioService的getMethod实现

去掉冗余的then,直接返回Dio请求的Future,让上层统一处理错误;也可以在内部添加基础错误捕获,但建议上层处理业务相关错误。

3. 修正错误处理逻辑

区分不同类型的Dio错误:

  • 有响应的错误(如401、404等):通过e.response?.statusCode判断
  • 无响应的错误(如连接失败、超时等):通过e.type判断

4. 规范isLoading状态管理

请求开始时立即设置isLoading为true,成功或失败后同步设置为false,避免延迟导致的状态不一致。

修正后的完整代码

JemaatController 修正版

class JemaatController extends GetxController {
  RxList<JemaatJSON> jemaat = RxList();
  RxBool isListViewScrollToTheDown = false.obs;
  RxBool isLoading = true.obs;
  RxBool isInternetConnect = true.obs;
  final deviceStorage = GetStorage();
  var url = "${ConfigBack.apiAdress}/admin/jemaat/";
  var itemController = ItemScrollController();

  getJemaat() async {
    isLoading.value = true; // 请求开始立即设为加载中
    try {
      var response = await DioService().getMethod(url);
      if (response.statusCode == 200) {
        jemaat.clear(); // 先清空旧数据再添加新数据
        response.data.forEach((element) {
          jemaat.add(JemaatJSON.fromJson(element));
        });
      }
    } catch (e) {
      isInternetConnect.value = false;
      if (e is DioException) {
        // 处理无响应的连接类错误
        if (e.type == DioExceptionType.connectionError || 
            e.type == DioExceptionType.connectionTimeout ||
            e.type == DioExceptionType.receiveTimeout) {
          FilemonHelperFunctions.showSnackBar(
              "Koneksi bermasalah, ini bukan pada perangkat anda");
        } 
        // 处理有响应的状态码错误
        else if (e.response?.statusCode == 401) {
          FilemonHelperFunctions.showSnackBar(
              "Waktu sesi telah berakhir silahkan Re-Log");
          deviceStorage.write('user_login', false);
          deviceStorage.write('IsFirstTime', false);
          deviceStorage.remove('usertoken');
          deviceStorage.remove('userC');
          NavigationAdmin().toMain();
        } 
        // 其他有响应的错误
        else {
          FilemonHelperFunctions.showSnackBar(
              "Error: ${e.response?.statusMessage ?? 'Unknown error'}");
        }
      } else {
        // 非Dio错误
        FilemonHelperFunctions.showSnackBar("Terjadi kesalahan: $e");
      }
    } finally {
      // 无论成功失败,最终都关闭加载状态
      isLoading.value = false;
    }
  }

  remJemaat() async {
    jemaat.clear();
  }

  scrollListViewDownward() {
    itemController.scrollTo(
        index: jemaat.length - 4,
        duration: const Duration(seconds: 2),
        curve: Curves.fastOutSlowIn);
    isListViewScrollToTheDown.value = true;
  }

  scrollListViewUpward() {
    itemController.scrollTo(
        index: 0,
        duration: const Duration(seconds: 2),
        curve: Curves.fastOutSlowIn);
    isListViewScrollToTheDown.value = false;
  }

  @override
  void onInit() {
    getJemaat();
    super.onInit();
  }
}

DioService 修正版

class DioService {
  Future<dynamic> getMethod(String url) async {
    dioUpers.Dio dio = dioUpers.Dio();
    dioUpers.Options options = 
        dioUpers.Options(headers: HeadersCode().data(), method: "GET");
    // 直接返回请求Future,让上层处理错误
    return await dio.get(url, options: options);
  }
}

关键说明

  • 使用finally块确保isLoading一定会被设置为false,避免请求失败时状态卡住
  • 拆分错误处理逻辑,分别处理连接类错误和状态码错误,避免逻辑嵌套错误
  • 请求开始时立即设置加载状态,提升用户体验
  • 清空旧数据再添加新数据,避免列表数据重复

内容的提问来源于stack exchange,提问作者Filemon Sitanggang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 06:32:08