首页 > 其他分享 >Flutter网络请求与dio实战指南

Flutter网络请求与dio实战指南

时间:2023-11-14 20:01:02浏览次数:25  
标签:指南 dio return String Flutter response options 请求

当在Flutter中进行网络请求时,dio是一个强大且常用的网络请求库。以下是使用dio实现网络请求的基本配置,包括GET和POST请求,以及文件上传和下载的功能。

首先,确保在pubspec.yaml文件中添加dio库的依赖:

dependencies:
  # https://github.com/flutterchina/dio
  dio: ^5.3.3

然后运行flutter pub get安装依赖。

下面是完整工具类代码:


import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';

import 'package:get/get.dart' as getx;

import '../../weight/loading.dart';
import 'api.dart';

class HttpUtil {
  static HttpUtil? instance;
  late Dio dio;
  late BaseOptions options;

  CancelToken cancelToken = CancelToken();

  static HttpUtil getInstance() {
    instance ??= HttpUtil();
    return instance!;
  }

  /*
   * config it and create
   */
  HttpUtil() {
    //BaseOptions、Options、RequestOptions 都可以配置参数,优先级别依次递增,且可以根据优先级别覆盖参数
    options = BaseOptions(
      //请求基地址,可以包含子路径
      baseUrl: Api.BASE_URL,
      //连接服务器超时时间,单位是秒.
      connectTimeout: const Duration(seconds: 10),
      //响应流上前后两次接受到数据的间隔,单位为秒。
      receiveTimeout: const Duration(seconds: 5),
      //Http请求头.
      headers: {
        "version": "1.0.0"
      },
      //请求的Content-Type,默认值是"application/json; charset=utf-8",Headers.formUrlEncodedContentType会自动编码请求体.
      contentType: Headers.formUrlEncodedContentType,
      //表示期望以那种格式(方式)接受响应数据。接受四种类型 `json`, `stream`, `plain`, `bytes`. 默认值是 `json`,
      responseType: ResponseType.plain,
    );

    dio = Dio(options);

    //Cookie管理
    final cookieJar = CookieJar();
    dio.interceptors.add(CookieManager(cookieJar));

    //添加拦截器
    dio.interceptors.add(InterceptorsWrapper(
        onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
      print("请求之前 header = ${options.headers.toString()}");
      // 打印查询参数
      if (options.queryParameters != null) {
        print("Query Parameters: ${options.queryParameters}");
      }
      // 如果你想完成请求并返回一些自定义数据,你可以使用 `handler.resolve(response)`。
      // 如果你想终止请求并触发一个错误,你可以使用 `handler.reject(error)`。
      return handler.next(options); //continue
    }, onResponse: (Response response, ResponseInterceptorHandler handler) {
      print("响应之前");
      // 如果你想终止请求并触发一个错误,你可以使用 `handler.reject(error)`。
      return handler.next(response); // continue
    }, one rror: (DioException e, ErrorInterceptorHandler handler) {
      print("错误之前");
      // 如果你想完成请求并返回一些自定义数据,你可以使用 `handler.resolve(response)`。
      return handler.next(e);
    }));
  }


  /*
   * GET请求
   */
  Future<Response?> getRequest(
      String url, {
        Map<String, dynamic>? parameters,
        Options? options,
        CancelToken? cancelToken,
        void Function(Response response)? onSuccess,
        void Function(String error)? one rror,
        bool showLoading = false,
        String loadingMsg = '请稍后...',
      }) async {
    try {
      _toggleLoading(showLoading, loadingMsg);
      final response = await dio.get(
        url,
        queryParameters: parameters,
        options: options,
        cancelToken: cancelToken,
      );
      _toggleLoading(showLoading, loadingMsg);
      if (onSuccess != null) {
        if (response.statusCode == 200) {
          onSuccess(response);
        } else {
          // 处理其他状态码的逻辑
          // ...
        }
      }
      return response;
    } on DioException catch (e) {
      _toggleLoading(showLoading, loadingMsg);
      if (onError != null) {
        one rror(_formatError(e));
      }
      return null;
    }
  }

  void _toggleLoading(bool showLoading, String loadingMsg) {
    if (showLoading) {
      LoadingIndicator.show(getx.Get.context!, title: loadingMsg);
    } else {
      LoadingIndicator.hide();
    }
  }

  /*
   * POST请求
   */
  Future<Response?> postRequest(
      String url, {
        Map<String, dynamic>? parameters,
        dynamic data,
        Options? options,
        CancelToken? cancelToken,
        void Function(Response response)? onSuccess,
        void Function(String error)? one rror,
        bool showLoading = false,
        String loadingMsg = '请稍后...',
      }) async {
    try {
      _toggleLoading(showLoading, loadingMsg);
      final response = await dio.post(
        url,
        data: data,
        queryParameters: parameters,
        options: options,
        cancelToken: cancelToken,
      );
      _toggleLoading(showLoading, loadingMsg);

      if (onSuccess != null) {
        if (response.statusCode == 200) {
          onSuccess(response);
        } else {
          // 处理其他状态码的逻辑
          // ...
        }
      }
      return response;
    } on DioError catch (e) {
      _toggleLoading(showLoading, loadingMsg);
      if (onError != null) {
        one rror(_formatError(e));
      }
      return null;
    }
  }

  /*
   * 下载文件
   */
  Future<dynamic> downloadFile(String urlPath, String savePath) async {
    Response? response;
    try {
      response = await dio.download(
        urlPath,
        savePath,
        onReceiveProgress: _onDownloadProgress,
      );
    } on DioError catch (e) {
      _formatError(e);
    }
    return response?.data;
  }

  // 提取进度回调
  void _onDownloadProgress(int count, int total) {
    // 进度
    print("$count $total");
  }

  /*
   * 上传文件
   */
  Future<void> uploadFile(url, FormData formData,
      {String? accessToken,
      Function(Response response)? onSuccess,
      Function(String error)? one rror}) async {
    try {
      late Response response;
      response = await dio.post(
        url,
        data: formData,
        options: Options(
          headers: {'Authorization': 'Bearer $accessToken'},
        ),
      );

      if (onSuccess != null) {
        if (response.statusCode == 200) {
          onSuccess(response);
        } else {
          // 处理其他状态码的逻辑
          // ...
        }
      }
      print('上传成功: ${response.data}');
    } on DioException catch (e) {
      if (onError != null) {
        one rror(_formatError(e));
      }
      print('上传失败: $e');
    }
  }

  /*
   * error统一处理
   */
  String _formatError(DioException e) {

    String errorMsg = '';
    if (e.type == DioExceptionType.connectionTimeout) {
      errorMsg =  '连接超时';
    } else if (e.type == DioExceptionType.sendTimeout) {
      errorMsg =  '请求超时';
    } else if (e.type == DioExceptionType.receiveTimeout) {
      errorMsg =  '响应超时';
    } else if (e.type == DioExceptionType.badResponse) {
      errorMsg =  '错误响应';
    } else if (e.type == DioExceptionType.cancel) {
      errorMsg =  '请求取消';
    } else if (e.type == DioExceptionType.connectionError) {
      errorMsg =  '无法连接服务器';
    } else {
      errorMsg =  '未知错误';
    }
    print(errorMsg);
    return errorMsg;
  }

  /*
   * 取消请求
   *
   * 同一个cancel token 可以用于多个请求,当一个cancel token取消时,所有使用该cancel token的请求都会被取消。
   * 所以参数可选
   */
  void cancelRequests(CancelToken token) {
    token.cancel("cancelled");
  }
}

代码中使用的dialog可以参考该链接



标签:指南,dio,return,String,Flutter,response,options,请求
From: https://blog.51cto.com/u_16319811/8377280

相关文章

  • Gson 指南
    https://blog.csdn.net/JonTang/article/details/132481485https://blog.csdn.net/u014212540/article/details/127687138com.google.code.gsongson2.8.0com.google.code.gsongson2.10.1在Maven中,如果子模块没有显式指定版本号,Maven会默认使用父工程的版本号作为子......
  • 从零到一:抖音小程序开发全指南及预算规划
    在数字时代,抖音小程序的开发成为企业实现品牌推广、服务提供的重要途径。本文将为您提供从零到一的抖音小程序开发全指南,包括预算规划以及一些关键的技术代码示例。1.项目准备在开始抖音小程序开发之前,需要进行一些项目准备工作。1.1定义项目目标//项目目标定义示例constproje......
  • cosbench压测指南
    COS压测指南COSBench简介COSBench是一款由Intel开源,用于对象存储的压测工具。腾讯云对象存储(CloudObjectStorage,COS)作为兼容S3协议的对象存储系统,可使用该工具进行读写性能压测。系统环境工具推荐运行在CentOS7.0及其以上版本,ubuntu环境可能存在预期外的问题。......
  • visualstudio+cmake+环境配置,及使用过程中的一些小坑点
    一、概述想要找一个免费好用的c++开发工具。期间尝试了eclipse+CDT、VSCode+Mingw64+CMake都觉得不是很好用。最后选择了社区版的VisualStudio+CMake。之所以选择这个,是因为相对于eclipse和VSCode这个更好用。就是使用过程中会遇到一些小问题。二、配置1.下载Vis......
  • Java开发者的Python快速进修指南:函数基础
    话不多说,今天我们要介绍的是函数。本系列文章追求短而精,今天我们将重点讨论函数以及与Java方法的区别。与Java方法不同,函数不需要像Java方法一样讲究修饰符等其他特性,它只需要使用"def"关键字进行声明。另外,函数的参数也与Java方法有所不同,Java方法中不存在默认参数的概念,而在Pyth......
  • Redis各种集群搭建指南
    Redis集群本章是基于CentOS7下的Redis集群教程,包括:单机安装RedisRedis主从Redis分片集群1.单机安装Redis首先需要安装Redis所需要的依赖:yuminstall-ygcctcl例如,我放到了/tmp目录:解压缩:tar-xzfredis-6.2.4.tar.gz解压后:进入redis目录:cdredis-6.2.4运行编译命令:make&&makei......
  • [左神面试指南] 递归和动态规划[上]篇
    CD183斐波那契数列问题的递归和动态规划1/**矩阵快速幂*[f(n),f(n-1)]=[1,1]x[[1,1],[1,0]]^(n-2)*/publicclassCD183_1{publicstaticlongsolution(longn){if(n<1)return-1;if(n<=2)return1;long[][]......
  • 现代移动应用开发的未来非Flutter莫属!
    前言Flutter是一种开源的移动应用开发框架,由Google推出,为开发者提供了一种全新的方式来构建跨平台的高性能应用程序。随着移动应用市场的快速发展和技术的不断进步,Flutter被认为是现代移动应用开发的未来。Flutter优势首先,Flutter具备卓越的性能和响应速度它采用了自己的渲染引擎,名......
  • 从混乱到优雅:基于DDD的六边形架构的代码翻新指南
    前言趁着双十一备战封板,终于又有一些时间可以梳理一下最近的心得。最近这半年跟同事讨论比较多的是分层架构,然后就会遇到两个触及灵魂的问题,一个是如何做好分层架构,二是DDD在架构层面该如何落地。为了说好分层,我们需要了解架构的意义。良好的架构是为了保证一下两点:治理应用......
  • Visual studio2022 配置Libtorch
    版本:gpu3090VisualStudio2022Cuda11.7下载libtorch文件,有release、debug版本和CPU版本。下面以release版本为例在VS2022中配置MKL1.配置环境变量PATH=C:\libtorch\libtorch-win-shared-with-deps-1.13.1+cu117\libtorch\lib;%PATH%2.配置C/C++--常规--附加包......