• flutter dio网络请求封装实现


    flutter dio网络请求封装实现

    文章友情链接:   https://juejin.im/post/6844904098643312648

    在Flutter项目中使用网络请求的方式大致可分为两种,分别是Dart原生的网络请求 HttpClient类以及第三方开源的网络请求库。在Dart社区开源的第三方http请求库中Flutter中文网开源的Dio库人气最高。
      下面我们先来比较下这两种网络请求方式,然后再看怎么基于 Dio库封装方便使用的网络请求工具类HttpManager。

    网络请求库比较

    HttClient类

    Dart IO库中提供了用于发起Http请求的一些类,我们可以直接使用HttpClient来发起请求。

    使用HttpClient发起请求共分为五步:

    1. 创建一个HttpClient
     HttpClient httpClient = new HttpClient();
    复制代码
    1. 打开Http连接,设置请求头
    HttpClientRequest request = await httpClient.getUrl(uri);
    复制代码

    这一步可以使用任意Http Method,如httpClient.post(...)、httpClient.delete(...)等。如果包含Query参数,可以在构建uri时添加,如:

    Uri uri=Uri(scheme: "https", host: "flutterchina.club", queryParameters: {
        "xx":"xx",
        "yy":"dd"
      });
    复制代码

    通过HttpClientRequest可以设置请求header,如:

    request.headers.add("user-agent", "test");
    复制代码

    如果是post或put等可以携带请求体方法,可以通过HttpClientRequest对象发送request body,如:

    String payload="...";
    request.add(utf8.encode(payload)); 
    //request.addStream(_inputStream); //可以直接添加输入流
    复制代码
    1. 等待连接服务器
    HttpClientResponse response = await request.close();
    复制代码

    这一步完成后,请求信息就已经发送给服务器了,返回一个HttpClientResponse对象,它包含响应头(header)和响应流(响应体的Stream),接下来就可以通过读取响应流来获取响应内容。

    1. 读取响应内容
    String responseBody = await response.transform(utf8.decoder).join();
    复制代码

    我们通过读取响应流来获取服务器返回的数据,在读取时我们可以设置编码格式,这里是utf8。

    1. 请求结束,关闭HttpClient
    httpClient.close();
    复制代码

    关闭client后,通过该client发起的所有请求都会中止。

      以上的步骤是dart原生网络HttpClient使用方式,可以发现直接使用HttpClient发起网络请求是比较麻烦的,很多事情都得手动处理,如果再涉及到文件上传/下载、Cookie管理等就会变得非常繁琐,并且HttpClient本身功能较弱,很多常用功能都不支持。

    Dio库

    dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时等...

    1. pubspec.yaml 添加依赖

            dependencies: dio: ^x.x.x #请使用pub上的最新版本

    1. 导入引用并创建dio 实例

    import 'package:dio/dio.dart';
    Dio dio = Dio();

    接下来就可以通过 dio实例来发起网络请求了,注意,一个dio实例可以发起多个http请求,一般来说,APP只有一个http数据源时,dio应该使用单例模式。

    1. 发起网络请求

    Get 请求

    Response response;
    response=await dio.get("/test?id=12&name=cheney")
    print(response.data.toString());

    Post请求

    Response response;
    response=await dio.post("/test",data:{"id":12,"name":"cheney"})
    print(response.data.toString());

    以上就是Dio库网络请求的基本使用,是不是很简单,除了这些基本的用法,dio还支持请求配置、拦截器等,官方资料比较详细,故在这里不再赘述,详情可以参考dio主页:github.com/flutterchin… 。

    封装Dio工具类

    为什么要封装 dio


     

    做一些公共处理,方便灵活的使用。

    做那些封装

    • 统一处理请求前缀;(www.xx.com/api/v1 不用每个请求都加前缀)
    • 统一输出请求或响应信息;
    • 统一错误信息处理;
    • 兼容多种网络请求、支持文件上传、下载;
    • 支持同步回调与异步Future 两种形式
    • 返回数据自动转json格式并默认解析公共数据模型;

    目录

    类名描述
    HttpManager 网络请求管理类
    HttpError 网络请求统一错误类
    LogInterceptor 网络请求工具类

    HttpManager

    import 'dart:core';
    
    import 'package:connectivity/connectivity.dart';
    import 'package:dio/dio.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_common_utils/http/http_error.dart';
    import 'package:flutter_common_utils/log_util.dart';
    
    ///http请求成功回调
    typedef HttpSuccessCallback<T> = void Function(dynamic data);
    
    ///失败回调
    typedef HttpFailureCallback = void Function(HttpError data);
    
    ///数据解析回调
    typedef T JsonParse<T>(dynamic data);
    
    
    /// @desc  封装 http 请求
    /// @time 2019/3/15 10:35 AM
    /// @author Cheney
    class HttpManager {
        init                        : 初始化baseUrl,超时时间等
        get                         : get请求同步回调
        post                        : post请求同步回调
        upload                      : 文件上传同步回调
        download                    : 文件下载同步回调
        getAsync                    : get 请求异步方式
        postAsync                   : post 请求异步方式
        uploadAsync                 : 文件上传异步方式
        downloadAsync               : 文件下载异步方式
        [...]
     }

    详细源码见最后

    这里处理了网络连接判断、取消网络请求、默认的数据格式解析等。 默认解析的数据格式:

    {
        "data":{},
        "statusCode":"0",
        "statusDesc":"02032008:用户授信未通过",
        "timestamp":1569206576392
    }

    大家可根据自己的需求更改成自己的数据格式处理

    HttpError

    import 'package:dio/dio.dart';
    
    /// @desc  网络请求错误
    /// @time 2019/3/20 10:02 AM
    /// @author Cheney
    class HttpError {
      ///HTTP 状态码
      static const int UNAUTHORIZED = 401;
      static const int FORBIDDEN = 403;
      static const int NOT_FOUND = 404;
      static const int REQUEST_TIMEOUT = 408;
      static const int INTERNAL_SERVER_ERROR = 500;
      static const int BAD_GATEWAY = 502;
      static const int SERVICE_UNAVAILABLE = 503;
      static const int GATEWAY_TIMEOUT = 504;
    
      ///未知错误
      static const String UNKNOWN = "UNKNOWN";
    
      ///解析错误
      static const String PARSE_ERROR = "PARSE_ERROR";
    
      ///网络错误
      static const String NETWORK_ERROR = "NETWORK_ERROR";
    
      ///协议错误
      static const String HTTP_ERROR = "HTTP_ERROR";
    
      ///证书错误
      static const String SSL_ERROR = "SSL_ERROR";
    
      ///连接超时
      static const String CONNECT_TIMEOUT = "CONNECT_TIMEOUT";
    
      ///响应超时
      static const String RECEIVE_TIMEOUT = "RECEIVE_TIMEOUT";
    
      ///发送超时
      static const String SEND_TIMEOUT = "SEND_TIMEOUT";
    
      ///网络请求取消
      static const String CANCEL = "CANCEL";
    
      String code;
    
      String message;
    
      HttpError(this.code, this.message);
    
      HttpError.dioError(DioError error) {
        message = error.message;
        switch (error.type) {
          case DioErrorType.CONNECT_TIMEOUT:
            code = CONNECT_TIMEOUT;
            message = "网络连接超时,请检查网络设置";
            break;
          case DioErrorType.RECEIVE_TIMEOUT:
            code = RECEIVE_TIMEOUT;
            message = "服务器异常,请稍后重试!";
            break;
          case DioErrorType.SEND_TIMEOUT:
            code = SEND_TIMEOUT;
            message = "网络连接超时,请检查网络设置";
            break;
          case DioErrorType.RESPONSE:
            code = HTTP_ERROR;
            message = "服务器异常,请稍后重试!";
            break;
          case DioErrorType.CANCEL:
            code = CANCEL;
            message = "请求已被取消,请重新请求";
            break;
          case DioErrorType.DEFAULT:
            code = UNKNOWN;
            message = "网络异常,请稍后重试!";
            break;
        }
      }
    
      @override
      String toString() {
        return 'HttpError{code: $code, message: $message}';
      }
    }

    这里设置了多种错误的描述,大家可根据需求修改。

    LogInterceptor

    import 'package:dio/dio.dart';
    import 'package:flutter_common_utils/log_util.dart';
    
    void log2Console(Object object) {
      LogUtil.v(object);
    }
    
    /// @desc  自定义日志拦截器
    ///@time 2019/3/18 9:15 AM
    /// @author Cheney
    class LogInterceptor extends Interceptor {
      LogInterceptor({
        this.request = true,
        this.requestHeader = true,
        this.requestBody = false,
        this.responseHeader = true,
        this.responseBody = false,
        this.error = true,
        this.logPrint = log2Console,
      });
    
      [...]
    }

    详细源码见最后

    这里默认使用 LogUtl 输出日志,大家可根据需要换成自己的日志输出工具类

    Step1: 初始化

    //初始化 Http,
      HttpManager().init(
        baseUrl: Api.getBaseUrl(),
        interceptors: [
          HeaderInterceptor(),
          LogInterceptor(),
        ],
      );

    Step2:创建网络请求

    ///同步回调模式
    ///get 网络请求
    void _get(){
       HttpManager().get(
          url: "/app/info",
          params: {"iouCode": iouCode},
          successCallback: (data) {
            
          },
          errorCallback: (HttpError error) {
           
          },
          tag: "tag",
        );
    }
    ///post 网络请求
    void _post(){
         HttpManager().post(
          url: "/app/info",
          data: {"iouCode": iouCode},
          successCallback: (data) {
            
          },
          errorCallback: (HttpError error) {
            
          },
          tag: "tag",
        );
    }
    
    ///下载文件
    void _download(){
         HttpManager().download(
          url: "/app/download",
          savePath: "/savePath",
          onReceiveProgress: (int count, int total) {
          },
          successCallback: (data) {
            
          },
          errorCallback: (HttpError error) {
            
          },
          tag: tag,
        );
    }
    
    ///上传文件
    void _upload() async{
    FormData data = FormData.fromMap({
            "file": await MultipartFile.fromFile(path, filename: "$photoTime"),
          });
        HttpManager().upload(
            url: "/app/upload",
            data: data,
            tag: "tag",
            successCallback: (data) {
              
            },
            errorCallback: (HttpError error) {
              
            },
          );
    }
    
    
    ///异步模式
    ///get 请求
    void _getAysnc() async{
         String timestamp =
            await HttpManager().getAsync(url: "/app/info", tag: "syncTime");
    }
    
    ///post 请求
    void _postAysnc() async{
       await HttpManager().postAsync(
            url: "app/info",
            tag: "tag",
            data: {
              'bannerTypes': ["wealthBanner"],
            },
            jsonParse: (json) => Pager(json, (data) => ImageAd(data)))
    }
    
    ///下载文件
    void _downloadAsync() async{
        await HttpManager().downloadAsync(
          url: "/app/download",
          savePath: "/savePath",
          onReceiveProgress: (int count, int total) {
          },
          tag: "tag",
        );
    }
    
    ///上传文件
    void _uploadAsync() async{
    FormData data = FormData.fromMap({
            "file": await MultipartFile.fromFile(path, filename: "$photoTime"),
          });
      await  HttpManager().uploadAsync(
            url: "/app/upload",
            data: data,
            tag: "tag",
           
          );
    }

    最后

      如果在使用过程遇到问题,欢迎下方留言交流。

      工具类库地址

    文章友情链接:   https://juejin.im/post/6844904098643312648

  • 相关阅读:
    多进程交替控制输出
    最长不重复子串
    const关键字的使用
    C++类的内存分布
    shell编程--awk 、sed 命令介绍
    gcc 6.0编译opencv出错
    NTP同步网络时间
    树莓派配置RTC时钟(DS3231,I2C接口)
    浏览器播放rtmp流
    nginx配置hls
  • 原文地址:https://www.cnblogs.com/maqingyuan/p/13656283.html
Copyright © 2020-2023  润新知