Flutter:处理错误Dio程序包(404,400等)

时间:2019-08-12 04:45:14

标签: flutter dart

我正在学习使用包 DIO https://pub.dev/packages/dio通过ID搜索数据,我的问题是每次我键入错误的关键字搜索时,应用都会突然崩溃,并显示调试消息找不到404 enter image description here
我知道找不到数据,因为我输入了错误的关键字,但是我已经可以使用此代码

Widget _searchKeywordMahasiswa() {
    return FutureBuilder<List<Mosque>>(
      future: api.getMahasiswaById(_searchText),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.hasData) {
          return Expanded(
            child: ListView.builder(
              shrinkWrap: true,
              itemCount: snapshot.data.length,
              itemBuilder: (BuildContext context, int index) {
                return Text(snapshot.data[index].id);
              },
            ),
          );
        } else if (!snapshot.data) { <<<<<< IN THIS LINE
          return Center(
            child: Icon(
              Icons.sentiment_very_dissatisfied,
              size: 150.0,
            ),
          );
        }
        return CircularProgressIndicator();
      },
    );
    // return CircularProgressIndicator();
  }
Future<List<Mosque>> getMahasiswaById(String id) async{
    try {
      var apiRespon = await dio.get('${Urls.BASE_API_URL}/mahasiswa/get/id/$id');
      var apiResponJson = apiRespon.data;
      print(apiResponJson);
      return (apiResponJson['data'] as List).map((p)=>Mosque.fromJson(p)).toList();

    }on DioError catch (e) { <<<<< IN THIS LINE
      if(e.response.statusCode == 404){
        print(e.response.statusCode);
      }else{
        print(e.message);
        print(e.request);
      }
    }
  }
  

在同一情况下,如果我遇到错误 400错误的请求,我的应用程序也会崩溃,并且我已经处理了此错误,但无法正常工作。

您能帮我吗?

谢谢。

9 个答案:

答案 0 :(得分:4)

我遇到了同样的问题,只是改变了我的拦截器工作

import 'package:dio/dio.dart';

class CustomInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    print("onRequest");
    return super.onRequest(options, handler);
  }

  @override
  Future onResponse(Response response, ResponseInterceptorHandler handler) {
    print("onResponse");
    return null;
  }

  @override
  Future onError(DioError err, ErrorInterceptorHandler handler) async {
    print("onError: ${err.response.statusCode}");
    return handler.next(err);  // <--- THE TIP IS HERE
  }
}

答案 1 :(得分:3)

 var response = await dio.delete(
          url,
          data: postData,
          options: Options(
            followRedirects: false,
            validateStatus: (status) {
              return status < 500;
            },
            headers: headers,
          ),
        );

请使用兄弟下面的代码,

在代码中添加followRedirects,validateStatus。

答案 2 :(得分:1)

删除'on DioError'-不幸的是,Dio无法处理也不会捕获一些错误(404、500s ...)-我的应用中也有类似的问题。 然后将代码更改为下面发布的代码,或使用其他逻辑“全部捕获”;)

} catch (e) {

    if (e is DioError) {
    //handle DioError here by error type or by error code

    } else {
    ...
    }
 //return empty list (you can also return custom error to be handled by Future Builder)
}

您应该正确处理Future Builder状态:snapshot.hasData,空数据和snapshot.hasError,以防止将来崩溃

答案 3 :(得分:1)

我也有类似的类型问题。

首先,尝试使用flutter run从命令提示符运行项目,看看是否出现任何问题。

如果命令提示符未显示任何问题并且您的应用程序运行平稳,则必须检查IDE。如果您使用的是VSCode,则切换到“调试是侧边栏”,请参阅“断点”部分中选中的选项。如果选中All Exceptions,则调试器将在每个异常时暂停。取消选中All ExceptionsUncaught Exceptions,然后尝试重新启动。

希望这可以解决您的问题。

Breakpoint Section Image

答案 4 :(得分:0)

此网址字符串模式为${Urls.BASE_API_URL}/mahasiswa/get/id/$id

时出错

您不能使用。运算符,并从“”内的任何对象访问内部值。您可以将确切的url存储在其他变量中,并在该行中使用它。代码应如下。

Future<List<Mosque>> getMahasiswaById(String id) async{
try {
  var baseURL = Urls.BASE_API_URL;
  var apiRespon = await dio.get('${baseURL}/mahasiswa/get/id/$id');
  var apiResponJson = apiRespon.data;
  print(apiResponJson);
  return (apiResponJson['data'] as List).map((p)=>Mosque.fromJson(p)).toList();

}on DioError catch (e) { <<<<< IN THIS LINE
  if(e.response.statusCode == 404){
    print(e.response.statusCode);
  }else{
    print(e.message);
    print(e.request);
  }
}
}

答案 5 :(得分:0)

您可以使用 DioClient 管理超时异常:

有两种方法,声明自定义的 Option 然后分配给 Dio 或直接在 option 下面分配给它,但我更喜欢将这些类型的 Option 分开导向的需要。 可以设置条件获取除400(成功)响应以外的所有问题,但是要注意Connection Timeout,所以这里集成了一个Dio方式:

class YourRepositary {
  Dio dioClient;

  YourRepositary() {
    if (dioClient == null) {
      BaseOptions options = new BaseOptions(
          baseUrl: "YOUR_APIs_BASE_URL",
          receiveDataWhenStatusError: true,
          connectTimeout: 30000, // 30 seconds
          receiveTimeout: 30000 // 30 seconds
          );

      dioClient = new Dio(options);
    }
  }

  Future<ProductResponseModel> getProduct(var productRequestInputDto) async {
    try {
      Response response = await dio.post("/api/getProduct", data: productRequestInputDto);
      final ProductResponseModel _productModel = ProductResponseModel.fromJson(response.data);
      return _productModel ;
    } on DioError  catch (ex) {
      if(ex.type == DioErrorType.CONNECT_TIMEOUT){
        throw Exception("Connection Timeout Exception");
      }
      throw Exception(ex.message);
    }
  }

}

最后,下面的示例演示了您如何处理超时异常,甚至是如何处理 API 调用中的后端 500 错误:

void getProduct(){
 ProductRequestInputDto productRequest = new ProductRequestInputDto(productId: "666");

        var requestBody = jsonEncode(loginRequest);
        debugPrint("Request Data : $requestBody");

        _apiRepositary.getProduct(requestBody).then((response){
          debugPrint("Login Success $response");
          //manage your response here 
         },
          onError: (exception){
              //Handle exception message
            if(exception.message != null ){
              debugPrint(exception.message); // Here you get : "Connection  Timeout Exception" or even handled 500 errors on your backend.
            }
          },
        );
}

总而言之,这完全是关于 receiveDataWhenStatusError: true,在 Dio 的选项中。

答案 6 :(得分:0)

  dynamic _decodeErrorResponse(dynamic e) {
    dynamic data = {"statusCode": -1, "message": "Unknown Error"};
    if (e is DioError) {
      if (e.type == DioErrorType.response) {
        final response = e.response;
        try {
          if (response != null && response.data != null) {
            final Map responseData =
                json.decode(response.data as String) as Map;
            data["message"] = responseData['message'] as String;
            data["statusCode"] = response.statusCode;
          }
        } catch (e) {
          data["message"] = "Internal Error Catch";
        }
      } else if (e.type == DioErrorType.connectTimeout ||
          e.type == DioErrorType.receiveTimeout ||
          e.type == DioErrorType.sendTimeout) {
        data["message"] = "Request timeout";
        data["statusCode"] = 408;
      } else if (e.error is SocketException) {
        data["message"] = "No Internet Connection!";
      }
    }
    return data;
  }

答案 7 :(得分:0)

找到了解决办法。这段代码对我有用。

try {
  Dio dio = Dio();
  var res = await dio.download(
    url + 'fg',
    savePath.path + "/filename.bin",
    onReceiveProgress: (count, total) {
      progress(count, total);
    },
  );
} on DioError catch (e) {
  if (e.type == DioErrorType.response) {
    print('catched');
    return;
  }
  if (e.type == DioErrorType.connectTimeout) {
    print('check your connection');
    return;
  }

  if (e.type == DioErrorType.receiveTimeout) {
    print('unable to connect to the server');
    return;
  }

  if (e.type == DioErrorType.other) {
    print('Something went wrong');
    return;
  }
  print(e);
} catch (e) {
  print(e);
}

答案 8 :(得分:0)

所选答案运行良好。但是如果有人在添加这些行后仍然收到错误。你可以试试这个。

向字段添加内容类型。

dio.FormData formData = dio.FormData.fromMap({
      "file": await dio.MultipartFile.fromFile(
        file.path,
        filename: fileName,
        contentType: MediaType('audio', 'mp4'),
      ),