Flutter網(wǎng)絡(luò)請求框架封裝

版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請注明出處颓芭!
網(wǎng)絡(luò)請求是每個項目中都非常重要的一個環(huán)節(jié)顷锰,在Flutter中也有多種方式,這邊我使用到的是dio庫亡问,這是一個API非常完整的庫官紫,具體的介紹和使用我這里就不做過多的介紹,大家去從這個鏈接去看看(dio)就行州藕。
為了更加方便我們的使用束世,我對其再做一層封裝,里面會包含各種表單提交方式慎框,json提交方式等良狈,另外還包含一個統(tǒng)一的登錄異常的監(jiān)聽,和一個統(tǒng)一的數(shù)據(jù)處理和統(tǒng)一的異常處理等笨枯。下面還是老樣子薪丁,我們具體代碼中見:

class NetUtil {
  static final debug = false;
  static BuildContext context = null;
  /// 服務(wù)器路徑
  static final host = 'http://xxxxxxxx';
  static final baseUrl = host + '/api/';

///  基礎(chǔ)信息配置
  static final Dio _dio = new Dio(new Options(
      method: "get",
      baseUrl: baseUrl,
      connectTimeout: 5000,
      receiveTimeout: 5000,
      followRedirects: true));

 /// 代理設(shè)置,方便抓包來進(jìn)行接口調(diào)節(jié)

//  static void setProxy() {
//    _dio.onHttpClientCreate = (HttpClient client) {
//      // config the http client
//      client.findProxy = (uri) {
//        //proxy all request to localhost:8888
//        return "PROXY 192.168.1.151:8888";
//      };
//      // you can also create a new HttpClient to dio
//      // return new HttpClient();
//    };
//  }


  static String token;

  static final LogicError unknowError = LogicError(-1, "未知異常");

  static Future<Map<String, dynamic>> getJson<T>(
          String uri, Map<String, dynamic> paras) =>
      _httpJson("get", uri, data: paras).then(logicalErrorTransform);

  static Future<Map<String, dynamic>> getForm<T>(
          String uri, Map<String, dynamic> paras) =>
      _httpJson("get", uri, data: paras, dataIsJson: false)
          .then(logicalErrorTransform);

  /// 表單方式的post
  static Future<Map<String, dynamic>> postForm<T>(
          String uri, Map<String, dynamic> paras) =>
      _httpJson("post", uri, data: paras, dataIsJson: false)
          .then(logicalErrorTransform);

  /// requestBody (json格式參數(shù)) 方式的 post
  static Future<Map<String, dynamic>> postJson(
          String uri, Map<String, dynamic> body) =>
      _httpJson("post", uri, data: body).then(logicalErrorTransform);

  static Future<Map<String, dynamic>> deleteJson<T>(
          String uri, Map<String, dynamic> body) =>
      _httpJson("delete", uri, data: body).then(logicalErrorTransform);

  /// requestBody (json格式參數(shù)) 方式的 put
  static Future<Map<String, dynamic>> putJson<T>(
          String uri, Map<String, dynamic> body) =>
      _httpJson("put", uri, data: body).then(logicalErrorTransform);

  /// 表單方式的 put
  static Future<Map<String, dynamic>> putForm<T>(
          String uri, Map<String, dynamic> body) =>
      _httpJson("put", uri, data: body, dataIsJson: false)
          .then(logicalErrorTransform);

  /// 文件上傳  返回json數(shù)據(jù)為字符串
  static Future<T> putFile<T>(String uri, String filePath) {
    var name =
        filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length);
    var suffix = name.substring(name.lastIndexOf(".") + 1, name.length);
    FormData formData = new FormData.from({
      "multipartFile": new UploadFileInfo(new File(filePath), name,
          contentType: ContentType.parse("image/$suffix"))
    });

    var enToken = token == null ? "" : Uri.encodeFull(token);
    return _dio
        .put<Map<String, dynamic>>("$uri?token=$enToken", data: formData)
        .then(logicalErrorTransform);
  }

  static Future<Response<Map<String, dynamic>>> _httpJson(
      String method, String uri,
      {Map<String, dynamic> data, bool dataIsJson = true}) {
    var enToken = token == null ? "" : Uri.encodeFull(token);

    /// 如果為 get方法馅精,則進(jìn)行參數(shù)拼接
    if (method == "get") {
      dataIsJson = false;
      if (data == null) {
        data = new Map<String, dynamic>();
      }
      data["token"] = token;
    }

    if (debug) {
      print('<net url>------$uri');
      print('<net params>------$data');
    }

    /// 根據(jù)當(dāng)前 請求的類型來設(shè)置 如果是請求體形式則使用json格式
    /// 否則則是表單形式的(拼接在url上)
    Options op;
    if (dataIsJson) {
      op = new Options(contentType: ContentType.parse("application/json"));
    } else {
      op = new Options(
          contentType: ContentType.parse("application/x-www-form-urlencoded"));
    }

    op.method = method;

    /// 統(tǒng)一帶上token
    return _dio.request<Map<String, dynamic>>(
        method == "get" ? uri : "$uri?token=$enToken",
        data: data,
        options: op);

  }

  /// 對請求返回的數(shù)據(jù)進(jìn)行統(tǒng)一的處理
  /// 如果成功則將我們需要的數(shù)據(jù)返回出去严嗜,否則進(jìn)異常處理方法,返回異常信息
  static Future<T> logicalErrorTransform<T>(Response<Map<String, dynamic>> resp) {
    if (resp.data != null) {
      if (resp.data["code"] == 0) {
        T realData = resp.data["data"];
        return Future.value(realData);
      }
    }

    if (debug) {
      print('resp--------$resp');
      print('resp.data--------${resp.data}');
    }

    LogicError error;
    if (resp.data != null && resp.data["code"] != 0) {
      if (resp.data['data'] != null) {
        /// 失敗時  錯誤提示在 data中時
        /// 收到token過期時  直接進(jìn)入登錄頁面
        Map<String, dynamic> realData = resp.data["data"];
        error = new LogicError(resp.data["code"], realData['codeMessage']);
      } else {
        /// 失敗時  錯誤提示在 message中時
        error = new LogicError(resp.data["code"], resp.data["message"]);
      }
    } else {
      error = unknowError;
    }
    return Future.error(error);
  }

  ///獲取授權(quán)token
  static getToken() async {
    String token = await LocalStorage.get(LocalStorage.TOKEN_KEY);
    return token;
  }
}

/// 統(tǒng)一異常類
class LogicError {
  int errorCode;
  String msg;

  LogicError(errorCode, msg) {
    this.errorCode = errorCode;
    this.msg = msg;
  }
}

上面就完成了基本的封裝洲敢,基本涵蓋了所有的方法漫玄,除了下載,下面我們再來看看統(tǒng)一的登錄異常的處理压彭,當(dāng)監(jiān)聽到異地登錄的情況或者其他登錄異常時睦优,我們是需要讓用戶知道的,有時候還需要直接進(jìn)入登錄頁面壮不,這里就涉及到了路由的跳轉(zhuǎn)汗盘,需要context這個參數(shù),為了得到這個context询一,這時候我們可以寫一個監(jiān)聽類來結(jié)合接口使用

class LoginInvalidHandler {
  BuildContext currentContext;
  LoginInvalidHandler(this.currentContext);

  Future<Null> loginInvalidHandler(dynamic errorMsg) {
    if (errorMsg != null &&
        errorMsg is LogicError &&
        errorMsg.errorCode == 10000) {
      LocalStorage.clearLoginInfo();
      Fluttertoast.showToast(
          msg: '您的登錄已過期隐孽,請重新登錄',
          gravity: ToastGravity.CENTER,
          timeInSecForIos: 3);
/// 進(jìn)入登錄頁的路由跳轉(zhuǎn)
     // NavigatorUtils.goPwdLogin(currentContext);
      return Future.error(errorMsg);
    }
    return Future.error(errorMsg);
  }
}


Future<Null> nullFutureHandler(dynamic data){
  return Future.value(null);
}

有了這些以后嗎癌椿,一切都準(zhǔn)備好了,接下來就是接口了菱阵,我們可以寫一個Api類,這里我就簡單的寫兩個接口示例:

/// 所有接口請求

class ApiInterface {
  /// 獲取短信驗證碼
  static final String _API_GET_SMS = "user/sendPhoneSms";

  static Future<Map<String, dynamic>> getSmsCode(
      String flag, String phoneNum, String vefifyCode) async {
/// 調(diào)用封裝的NetUtil 踢俄,這里合理選擇方法即可,比如請求體的方式傳參數(shù)
    return NetUtil.postJson(_API_GET_SMS,
        {"flagId": flag, "phone": phoneNum, "vefifyCode": vefifyCode});
  }

/// 在需要進(jìn)行登錄校驗的接口上進(jìn)行LoginInvalidHandler  異常檢測 
///     LoginInvalidHandler handler 帶token過期  自動進(jìn)入登錄頁的 檢測
/// 這里使用的putForm 晴及,即表單方式傳遞參數(shù)
static final String _API_SET_PPWD = "user/set/word";
  static Future<Map<String, dynamic>> tradepassword(LoginInvalidHandler handler,
      String tradePassword, String checkTradePassword) async {
    return NetUtil.putForm(_API_SET_PPWD, {
      'tradePassword': tradePassword,
      'checkTradePassword': checkTradePassword
    }).catchError(handler.loginInvalidHandler);
  }

最后就是進(jìn)行調(diào)用了

 /// 調(diào)用
ApiInterface.tradepassword(
        LoginInvalidHandler(context), ‘sss’,'kjkkl') .then((data) {
 /// 請求成功 進(jìn)行成功的邏輯處理

}).catchError((errorMsg) {
 /// 請求失敗  進(jìn)入了自定義的error攔截
  if (errorMsg is LogicError) {
    LogicError logicError = errorMsg;
  
  } else {
 /// 請求失敗 dio異常
    
  }
});

進(jìn)行了上述的封裝之后都办,我們用起來就非常的順手了,寫起代碼來那是鍵盤敲得飛起奥羌凇脆丁!

喜歡的小伙伴們點點 贊哦!

代碼來啦Github傳送門
喜歡的話动雹,麻煩點點star哦!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末跟压,一起剝皮案震驚了整個濱河市胰蝠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌震蒋,老刑警劉巖茸塞,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異查剖,居然都是意外死亡钾虐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進(jìn)店門笋庄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來效扫,“玉大人,你說我怎么就攤上這事直砂【剩” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵静暂,是天一觀的道長济丘。 經(jīng)常有香客問我,道長洽蛀,這世上最難降的妖魔是什么摹迷? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮郊供,結(jié)果婚禮上峡碉,老公的妹妹穿的比我還像新娘。我一直安慰自己颂碘,他們只是感情好异赫,可當(dāng)我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布椅挣。 她就那樣靜靜地躺著,像睡著了一般塔拳。 火紅的嫁衣襯著肌膚如雪鼠证。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天靠抑,我揣著相機與錄音量九,去河邊找鬼。 笑死颂碧,一個胖子當(dāng)著我的面吹牛荠列,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播载城,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼肌似,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了诉瓦?” 一聲冷哼從身側(cè)響起川队,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎睬澡,沒想到半個月后固额,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡煞聪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年斗躏,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昔脯。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡啄糙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出栅干,到底是詐尸還是另有隱情迈套,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布碱鳞,位于F島的核電站桑李,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏窿给。R本人自食惡果不足惜贵白,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望崩泡。 院中可真熱鬧禁荒,春花似錦、人聲如沸角撞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至热康,卻和暖如春沛申,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背姐军。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工铁材, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奕锌。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓著觉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親惊暴。 傳聞我的和親對象是個殘疾皇子饼丘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容