美文网首页Flutter圈子
flutter网络请求

flutter网络请求

作者: jhxlx | 来源:发表于2020-03-12 10:34 被阅读0次

在flutter中进行网络请求有多种方式,这里我使用的是dio。dio这个库被封装的很好,使用起来也很简单,但为了更方便我还是自己在做了简单的封装。整体代码如下

class HttpRequestManager{

  factory HttpRequestManager() =>getInstance();

  static HttpRequestManager get instance =>getInstance();

  static HttpRequestManager _instance;

  Dio dio;

  static CancelToken cancelToken;


  String baseUrl="http://cardapi.mimiplay.cn/cardtest-api/";

  String baseTestUrl="http://cardapi.mimiplay.cn/cardtest-api/";


  HttpRequestManager._init(){
    dio=new Dio();

    BaseOptions options=BaseOptions(
      baseUrl:GlobalData.isProduct? baseUrl:baseTestUrl,
      connectTimeout: 20000,
      receiveTimeout: 20000,
      headers: {
        "content-type": "application/json;charset=UTF-8"
      },
      contentType: Headers.jsonContentType,//请求类型
      responseType: ResponseType.json,//接收类型
    );
    dio.options=options;

    cancelToken=new CancelToken();

    dio.interceptors.add(InterceptorsWrapper(//拦截器
        onRequest: (RequestOptions options){
          LogOut.I("请求地址:   ${options.uri}");
          LogOut.I("请求参数:   ${options.data}");
        },
        onResponse: (Response e){
//          if (e.statusCode==200) {
//            Map map=json.decode(e.data);
//            BaseResult<T> data=BaseResult.fromJson(map);
//          }
          LogOut.I("服务器返回数据----- ${e.toString()}");
        }
    ));
  }

  static HttpRequestManager getInstance(){
    if (_instance==null) {
      _instance=new HttpRequestManager._init();
    }
    return _instance;
  }

}

代码也很简单,就是在单例类里对dio进行一些设置,比如请求超时,请求头,返回类型等。然后也可以为其设置拦截,拦截有三个方法分别是
onrequest:可以在此方法内设置请求前的操作,比如设置token等,我这里只是打印了请求地址和参数
onResponse:此处拦截工作在数据返回之后,可以在方法内对dio请求的数据做二次封装或者转实体类等相关操作
onError:处理错误

做完了对dio的基本封装,下面就看下怎么使用其做网络请求,并对数据进行网络解析。具体代码如下

typedef CallBackSuccess =Function(BaseResult result);//设置请求成功方法
typedef CallBackFail =Function(String message);//设置请求失败方法



class HttpRequest{

  static void postRequest(String url,{Map<String, dynamic> data,CancelToken cancelToken,Options options,CallBackSuccess success,CallBackFail fail}) async{
    try {
      options=options??Options(method: "POST");//默认请求方法为post
      Response response= await HttpRequestManager.instance.dio.request
        (url,data:data,cancelToken:cancelToken,options: options);

      if (response.statusCode==200) {


        Map<String, dynamic> map=json.decode(response.toString());//请求成功将数据转化成map
        LogOut.I("data类型 ${map["data"].runtimeType}");//得到map里data的数据类型,方便接下来根据数据类型做解析
        BaseResult result;//数据基类

        if (map["data"] == null) {//data为null
          result=BaseResult.fromNoData(map);
        }else if (map["data"] is Map) {//data为map类型
          result=BaseResult.fromJson(map);
        }else if(map["data"] is List){//data为list类型
          LogOut.I("list类型");
          result=BaseResult.fromJsonList(map);
        }else if(map["data"] is String){//data为字符串
          result=BaseResult.fromString(map);
        }

        if(result.code=="900002"){
          //todo 登录失效处理
          Fluttertoast.showToast(msg: result.message);
          SPUtil util=await SPUtil.getInstances();
          await util.setString("userId", "");
          await util.setString("tokenId", "");
          await util.setString("phone", "");
          LogOut.I("登录失效");
          fail(result.message);
          MyRouters.navigatorKey.currentState.push(MaterialPageRoute(builder: (context){
            return new LoginPage();//登陆失效返回登录页
          },));
        }else{
          if (success!=null) {
            success(result);
          }
        }
      }else{
        if (fail!=null) {
          fail(response.statusMessage+"错误地址:$url");
        }else{
          Fluttertoast.showToast(msg: response.statusMessage);

        }
      }
    } catch (e) {
      print(e);
      if (fail!=null) {
        fail(e.toString()+"错误地址:$url");
      }
//      callBack.fail(e.toString()+"错误地址:$url");

    }
  }
}

在上面的代码中,网络请求方法默认为post,同时也做了数据解析。在flutter中数据解析不想Android那样方便,我这里是对其进行了分类型解析,这样不管后台返回的data为何种类型都有对应的解析方式。解析成功后就是看自己的需求做操作了,我在这里做了登录失效和请求成功的处理。成功时,将baseresult传入success方法里。至于baseresult是怎么分类型进行解析的,我这里借助了FlutterJsonBeanFactory这个插件实现的。下面看baseresult的具体代码

class BaseResult<T>{
  String code;
  String message;

  List<dynamic> listResult;

  Map<String, dynamic> result;

  String data;

  BaseResult({this.code, this.message, this.listResult,this.result,this.data});

  factory BaseResult.fromJsonList(Map<String, dynamic> json) {//data为list
    return BaseResult(
      code:json['code'],
      message: json['message'],
      listResult: json['data'],
    );

  }

  factory BaseResult.fromNoData(Map<String, dynamic> json) {//data为空
    return BaseResult(
      code:json['code'],
      message: json['message'],
    );
  }

  factory BaseResult.fromJson(Map<String, dynamic> json) {//data为map
    return BaseResult(
      code:json['code'],
      message: json['message'],
      result: json['data'],
    );

  }

  factory BaseResult.fromString(Map<String, dynamic> json) {//data为lString
    return BaseResult(
      code:json['code'],
      message: json['message'],
      data: json['data'],
    );

  }

  List<T> getListData<T>(){//data为list,得到data
    List<T> list=new List<T>();
    if (listResult!=null) {
      listResult.forEach((value) {
        list.add(JsonConvert.fromJsonAsT<T>(value));//插件方法
      });

    }
    return list;
  }


  T getMapData<T>(){//data为map,得到data
    LogOut.I("result $result");
    return JsonConvert.fromJsonAsT<T>(result);//插件方法
  }

  String getData(){//data为string,得到data
    return data;
  }


  @override
  String toString() {
    return 'BaseResult{code: $code, message: $message, listResult: $listResult, result: $result, data: $data}';
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['code'] = this.code;
    data['message'] = this.message;
    if (this.result != null) {
      data['data'] = this.result;
    }else if(this.listResult != null){
      data['data'] = this.listResult;
    }else if(this.data!=null){
      data['data'] = this.data;
    }
    return data;
  }
}

上面网络封装和数据解析都已经准备好了,接下来就是调用的问题了,我这里做了一个类专门放各个接口请求。具体代码如下

class RequestUtil{

  factory RequestUtil() =>getInstances();

  static RequestUtil get requestUtil =>getInstances();
  RequestUtil._init();

  static RequestUtil _requestUtil;

  static RequestUtil getInstances(){
    if (_requestUtil==null) {
      _requestUtil=new RequestUtil._init();

    }
    return _requestUtil;
  }

  Future<Map<String, dynamic>> _setBaseMap() async{//固定参数
    LoginManager loginManager=LoginManager.getInstances();
    LoginInfo info=await loginManager.getLogin();
    String userId=info.userId;
    String tokenId=info.tokenId;
    Map<String, dynamic> map={
      "userId":userId,
      "tokenId":tokenId,
      "clientVersion":clientVersion,
      "clientType":clientType
    };

    return map;
  }
///消息公告
  getMessage(Map<String, dynamic> data,{success(BaseResult result),fail(message)}) async{
    String url="notice/find/message";
    Map<String, dynamic> map=await _setBaseMap();
    map.addAll(data);
    HttpRequest.postRequest(url,data: map,success:success,fail: fail);
  }

///得到用户信息
  getUserInfo({success(BaseResult result),fail(message)}) async{
    String url="account/userAccount/108/myAccountInfo";
    Map<String, dynamic> map=await _setBaseMap();
    HttpRequest.postRequest(url,data: map,success:success,fail: fail);
  }
  ///登录
  doLogin(Map<String, dynamic> data,{success(BaseResult result),fail(message)}) async{
    String url="auth/login/normal";
    Map<String, dynamic> map=await _setBaseMap();
    map.addAll(data);
    HttpRequest.postRequest(url,data: map,success:success,fail: fail);
  }
}

然后就是调用了,这里展示data为map类型和list类型的调用。首先是map类型

 RequestUtil.getInstances().doLogin({
      "userMobileNo":userPhone,
      "userPass":pass,
    }, success: (result){//成功回调
      LoginResult resultLogin=result.getMapData<LoginResult>();//通过baseresult的getMapData得到data
      LogOut.I("${resultLogin.toString()}");
    },fail: (message){

    });

然后是list类型

void getMessage(){
    RequestUtil.getInstances().getMessage({
      "pageNum":1,
      "pageSize":15
    }, success: (result){
      controller.refreshCompleted();
      List<MessageResult> list=result.getListData<MessageResult>();//通过baseresult的getListData得到data
   
      LogOut.I("解析后 $list");
    },fail: (message){
    });
  }

到这里就将我自己做的flutter关于dio的网络请求与数据解析说完了,我个人觉得比较烦人的还是在数据解析这方面,关于flutter的数据解析还有多种方法,比如使用json_serializable,我这里觉得这种方式比较舒服就是用了这种。

相关文章

  • Flutter 网络请求框架封装

    Flutter 请求网络的三种方式 flutter 请求网络的方式有三种,分别是 Dart 原生的网络请求 Htt...

  • Flutter 网络请求框架封装

    Flutter 请求网络的三种方式 flutter 请求网络的方式有三种,分别是 Dart 原生的网络请求 Htt...

  • Flutter常用的Package

    Flutter搜索库 网络 dio 网络请求 http 网络请求 connectivity 网络状态改变(i...

  • flutter网络请求封装

    Flutter 网络请求框架封装

  • Flutter dio网络请求需在请求secret后的方式二:匿

    上一篇: Flutter dio网络请求需在请求secret后的方式一:请求时判断下一篇Flutter dio网络...

  • flutter抓包

    前言 老项目集成flutter以后,flutter页面网络请求使用的dio框架,发现charles无法抓取请求包 ...

  • Flutter 网络请求

    HttpClient(Dart内置API) http第三方库 Dio第三方库 1.HttpClient(Dart内...

  • Flutter网络请求

    在Flutter中常见的网络请求方式有三种:HttpClient、http库、dio库;注意:async 和 aw...

  • flutter网络请求

    在flutter中进行网络请求有多种方式,这里我使用的是dio。dio这个库被封装的很好,使用起来也很简单,但为了...

  • Flutter网络请求

    一. 网络请求的方式 在Flutter中常见的网络请求方式有三种:HttpClient、http库、dio库; 1...

网友评论

    本文标题:flutter网络请求

    本文链接:https://www.haomeiwen.com/subject/shzejhtx.html