IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Flutter-网络请求封装 -> 正文阅读

[移动开发]Flutter-网络请求封装

一、前言

网络请求是我们App开发过程中的重要内容,大部分App都需要和服务器进行数据交互,因此在开发过程中,我们需要封装我们网络请求的代码,对request、response以及error做统一处理,减少业务开发中的样板代码。

二、使用dio进行网络通讯

2.1 配置网络请求的基本信息

关于dio的具体用法参考dio官方文档。按照下面方式配置dio package:

dependencies:
  dio: ^4.0.4

在网络请求中,我们通常需要配置服务器的地址以及超时等,这里我们新建一个http_config.dat文件,添加如下内容:

class HttpConfig {
  //接口基础地址
  static const baseUrl = 'https://httpbin.org';

  static const connectTimeout = 5000;

  static const receiveTimeout = 3000;

  //基础配置
  static final options = BaseOptions(
      baseUrl: baseUrl,
      connectTimeout: connectTimeout,
      receiveTimeout: receiveTimeout);
}

其他具体业务中关于网络请求的通用配置信息都可以在这里进行添加,这里只是一个参考方式。

2.2 单例Dio对象

dio的作者也提示我们,尽量使用单例模式,我们可以按下面的方式定义单例:

class DioManager {

  static final DioManager _instance = DioManager._internal();

  factory DioManager() => _instance;

  late Dio dio;

  DioManager._internal(){
    _initDio();
  }

  ///
  ///
  /// 完成DIO的基础配置
  ///

  void _initDio() {
    dio = Dio(HttpConfig.options);
    dio.interceptors.add(HeaderInterceptor());
    dio.interceptors.add(AccessTokenInterceptor());
    dio.interceptors.add(LogInterceptor());
  }
}

2.3 处理网络请求

处理网络请求可以单独定义一个Http_util.dart文件,内容封装网络常用的请求方法,比如get、post等。

这里参考以前Android官方的设计方法,定义一个model作为最终的返回对象,resource.dart

//业务code成功
const codeResponseSuccess = 1;
//其他未知错误
const codeErrorUnknown = -1;

///
/// 参考以前的Android架构设计方案,设计Resource统一返回值
///
///
class Resource {
  int code;
  String? msg;
  dynamic data;

  ///
  /// 业务请求成功,服务端返回业务code值为codeResponseSuccess
  ///
  Resource.success(this.data, {this.code = codeResponseSuccess});

  ///
  /// 业务code不为success或者其他错误
  ///
  Resource.error(this.msg, this.code);

  ///
  ///
  /// 业务流程是否正常
  ///
  bool isSuccess(){
    return code == codeResponseSuccess;
  }

解析来定义一个http_util.dart来处理网络请求的具体操作,如下所示:

const String methodPost = 'post';

const String methodGet = 'get';

class HttpUtil {
  ///
  /// get 请求
  ///
  ///
  static Future<Resource> get(String path,
      {Map<String, dynamic>? queryParameters,
      Options? options,
      CancelToken? cancelToken,
      ProgressCallback? onReceiveProgress}) async {
    return _sendRequest(methodGet, path, queryParameters, options, cancelToken,
        onReceiveProgress);
  }

  ///
  /// post 请求
  ///
  ///
  static Future<Resource> post(
    String path, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
  }) {
    return _sendRequest(methodPost, path, queryParameters, options, cancelToken,
        onReceiveProgress);
  }

  ///
  ///统一发送请求预计返回值统一处理
  ///
  static Future<Resource> _sendRequest(
    String method,
    String path,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
  ) async {
    var dio = DioManager().dio;
    try {
      Response? rsp;
      if (method == methodGet) {
        rsp = await dio.get(path, queryParameters: queryParameters);
      } else if (method == methodPost) {
        rsp = await dio.post(path, data: queryParameters);
      }
      if (rsp == null) return Resource.error('未知错误', codeErrorUnknown);
      return _handleResponse(rsp);
    } catch (err) {
      return Resource.error(_handleException(err), codeErrorUnknown);
    }
  }
}

_sendRequest的处理需要注意异常的处理,针对await的方式进行操作的,需要使用try/catch进行捕获异常。关于Future的理解和异常处理可参考:Flutter-了解Future及其用法

处理返回值:

返回值的处理需要根据服务定义的规范进行处理,这里使用的 https://httpbin.org 返回的数据格式进行解析处理:

  ///
  /// 统一处理解析数据
  ///
  static Resource _handleResponse(Response response) {
    if (_isSuccess(response.statusCode)) {
      var data = response.data['args'];
      var code = int.parse(data['code']);
      String msg = data['message'];
      if (code == codeResponseSuccess) {
        //这里尽量将业务中的code丢出去,方便开发中需要根据该code来进行一些特殊的处理
        return Resource.success(data['data'],code: code);
      } else {
        return Resource.error(msg, code);
      }
    } else {
      return Resource.error('未知错误', codeErrorUnknown);
    }
  }

  ///状态码是否成功
  static bool _isSuccess(int? statusCode) {
    return (statusCode != null && statusCode >= 200 && statusCode < 300);
  }

处理异常:

异常也是重要的一部分,可按照下面的方式进行异常处理,用于信息提示。

  ///
  /// 统一处理异常-返回错误信息
  ///
  static String _handleException(ex) {
    if (ex is DioError) {
      switch (ex.type) {
        case DioErrorType.connectTimeout:
        case DioErrorType.sendTimeout:
        case DioErrorType.receiveTimeout:
          return '网络超时';
        case DioErrorType.other:
          return '未知错误';
        case DioErrorType.response:
          int? statusCode = ex.response?.statusCode;
          switch (statusCode) {
            case 400:
              return '请求语法错误';
            case 401:
              return '没有权限';
            case 403:
              return '服务器拒绝执行';
            case 404:
              return '请求资源部存在';
            case 405:
              return '请求方法被禁止';
            case 500:
              return '服务器内部错误';
            case 502:
              return '无效请求';
            case 503:
              return '服务器异常';
            default:
              return '未知错误';
          }
        default:
          return '未知错误';
      }
    } else {
      return '未知错误';
    }
  }

2.3 业务中调用

在业务中调用就相对简单点了,直接使用HttpUtil.get或者post即可,如下:

  _testGetNedData() async {
    var param = {'code': 1, 'message': 'success', 'data': 'test net data'};
    var resource = await HttpUtil.get('/get', queryParameters: param);
    if (resource.isSuccess()) {
      //TODO 处理其他业务流程
      var data = resource.data;
      print('请求成功结果:$data');
    } else {
      print('请求错误:${resource.msg}');
    }
  }
  
   //或者
  _testGetNedData2() {
    var param = {'code': 1, 'message': 'success', 'data': 'test net data'};
    var resource = HttpUtil.get('/get', queryParameters: param);
    resource.then((value) {
      if (value.isSuccess()) {
        //TODO 处理其他业务流程
        var data = value.data;
        print('请求成功结果:$data');
      } else {
        print('请求错误:${value.msg}');
      }
    });
  }
    
    

根据以前Retrofit的写法,我们通常根据业务定义一个Service文件,统一封装和处理网络请求这块。这里我们定义个test_service.dart文件,如下:

///
/// 测试模块的统一请求处理
///
class TestService{

  ///
  ///业务1
  ///
  static Future<Resource> testOne(Map<String,dynamic> param){
    return HttpUtil.get('/get',queryParameters: param);
  }


  ///
  ///业务2
  ///
  static Future<Resource> testTwo(Map<String,dynamic> param){
    return HttpUtil.get('/get',queryParameters: param);
  }

}

接下来就可以在业务模块中直接调动该处理方法:

  _testGetNedData2() {
    var param = {'code': 1, 'message': 'success', 'data': 'test net data'};
    var resource = TestService.testOne(param);
    resource.then((value) {
      if (value.isSuccess()) {
        //TODO 处理其他业务流程
        var data = value.data;
        print('请求成功结果:$data');
      } else {
        print('请求错误:${value.msg}');
      }
    });
  }

这样做的好处就是方便后期的维护,后面上手的人可以根据该文件找到业务模块的网络请求方法,快速的维护。

最后

  1. 上述的实例展示基于dio的封装的业务调用方法的一部分,完成了一些基础的网络通讯功能,具体项目中使用,需要具体要求进行跳转,特别是http_util.dart中的_handleResponse进行修改
  2. 但是上述的封装还不能满足具体的项目要求,比如token和refreshToken的处理,以及其他一些通用的信息添加,这些放在后面的拦截器中进行处理。
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-01-25 10:42:32  更:2022-01-25 10:43:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:23:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码