react native 基于 fetch 簡單封裝自己的網(wǎng)絡(luò)請求

導語

在項目開發(fā)中,常用的工具類,我們都會專門封裝起來進行統(tǒng)一處理,方便以后統(tǒng)一調(diào)用、修改。網(wǎng)絡(luò)請求類算是用到最多的公共類之一了,本文就簡單來對 react native 的 fetch 進行簡單的封裝,并不會講述太多細節(jié),你可以使用你喜歡的搜索引擎去搜索 fetch api 關(guān)鍵字以了解更多信息。

參考

fetch api

  • method: 默認為 GET 請求
  • headers:請求頭 用來添加一些設(shè)備信息和用戶信息
  • body:請求體 請求參數(shù)

基本功能

  • 支持 GET POST 兩種請求 默認為 POST 請求
  • 支持自定義請求頭、傳入請求參數(shù)
  • 支持自定義請求超時時間
  • 支持請求中斷(防止重復發(fā)送同一個請求)
  • 便于擴展

接下來先看一下我們的網(wǎng)絡(luò)請求調(diào)用方式
第一步:創(chuàng)建,繼承封裝好的 fetch 類 重寫一下 requestUrl 方法

class XXXRequest extends BaseRequest{
  requestUrl() {
     return 'api/xxx.xxx';
}

第二步:使用

//創(chuàng)建一個請求對象,參數(shù)為(請求體,請求方法)
XXXRequest request = new XXXRequest();
// timeout 超時時間 單位為 s
// 顯示網(wǎng)絡(luò)請求加載動畫
request.timeout(10).showLoadingView().start(
     // 成功的回調(diào)
     (success)=>{
     },
     // 失敗的的回調(diào)
    (error)=>{
   });
// 中斷本次請求
request&&request.setCancled(true);

接下來直接上代碼 我會在代碼里面進行詳細的講解

/**
* Created by jzz on 2017/8/25.
*/

import  {
   Platform,
   BackAndroid,
   Alert,
}from 'react-native'

// 是否開啟 debug 模式
const DEBUG_MODE = true;
// 默認超時時間 20s
const TIMEOUT = 20;
export default class BaseRequest {
   // 構(gòu)造
   constructor(body, method, mode) {
       // 是否終止請求 默認false
       this.isCancled = false;
       // 請求失敗是否打印后臺message 默認false
       this.isShowMessage = false;
       if (body == null) {
           body = {};
       }
       // 默認的一些參數(shù)比如 版本號 token 
       Object.assign(body, {
           // version: version
           // access_token: testToken
       });
       // 當沒有指定請求方法的時候默認post
       if (method == null) {
           method = 'POST';
       }
       if (mode == null) {
           mode = 'cors';
       }
       this.method = method;
       this.body = body;
       this.mode = mode;
       this.headers = {
           'Accept': 'application/json',
           'Content-Type': 'application/json',
           // 在這里可以添加你需要添加的請求頭參數(shù)
           // 如 用戶 token、手機設(shè)備號等等
       };
       // 擴展 網(wǎng)絡(luò)請求耗時
       this.requestTime = this.getDefaultTestingTime();
      // 默認超時時間
      // 想要超時時間生效 必須修改 fetch 的源碼 在發(fā)請求之前加上如下代碼 (路徑為node_modules下的fetch.js的 self.fetch 方法里面)
      // if(init&&init!==null&&typeof init.timeout!=='undefined'){
      //     xhr.timeout=init.timeout;
      // }
       this.requestTimeout = TIMEOUT;
   }

   /**
    * 請覆蓋此方法
    */
   requestUrl() {
       throw ({message: 'function requestUrl must be overrided!'});
   }

   /**
    * 開啟加載動畫
    * 如果需要加載動畫可以在這里面去出路
    * 這里在用 redux 去控制顯示加載
    * 可以在這里面添加調(diào)用加載動畫的代碼 
    * @returns {BaseRequest}
    */
   showLoadingView() {
       this.isShowing = true;
       // 沒有刪除自己的 redux
       //store.dispatch(DialogAction.showLoading(true))
       return this;
   }

   /**
    * 關(guān)閉dialog
    * @returns {BaseRequest}
    */
   dismissLoadingView() {
       this.isShowing = false;
       // store.dispatch(DialogAction.showLoading(false))
       return this;
   }

   /**
    * 設(shè)置超時時間 如果不設(shè)置默認20s
    */
   timeout(timeout) {
       this.requestTimeout = typeof timeout === 'number' ? (timeout > 0 ? timeout : TIMEOUT) : TIMEOUT ;
       return this;
   }

   /**
    * 開始請求
    * @param successCallBack 成功后的回調(diào)
    * @param failCallBack 失敗后的回調(diào)
    * @returns {BaseRequest}
    */
   start(successCallBack, failCallBack) {
       //接口響應時間測試
       if (this.requestTime) {
           this.startTime = new Date().getTime();
       }
       //監(jiān)聽android返回鍵,android
       let url = this.requestUrl();
       if (this.isShowing) {
           BackAndroid.addEventListener(url, () => {
               this.dismissLoadingView();
               BackAndroid.removeEventListener(url);
               return false;
           });
       }
       this._doPost(successCallBack, failCallBack);
       return this;
   }

   /**
    * 開始請求
    * @param successCallBack 成功后的回調(diào)
    * @param failCallBack 失敗后的回調(diào)
    * @returns {BaseRequest}
    */
   async _doPost(successCallBack, failCallBack) {
       try {
           let url = this.getBaseUrl() + this.requestUrl();
           if ('GET' === this.method) {
               let str = this.toQueryString(this.body);
               if (str && str.length > 0) url += '?' + str;
           }
           this.showLog('requestUrl==>' + url);
           this.showLog(this.body);
           let response = await fetch(url, {
               headers: this.headers,
               method: this.method,
               mode: this.mode,
               body: this.method == 'GET' ? null : JSON.stringify(this.body),
               timeout: this.requestTimeout * 1000,
               // credentials: 'include',
           });
           let responseJson = await response.json();
           // console.log('---> BaseRequest start body' + JSON.stringify(this.body));
           this.showLog('response==>' + responseJson);
           this.showLog(responseJson);
           if (this.isShowing) {
               this.dismissLoadingView();
           }
           if (responseJson && !this.isCancled) {
               this.handleResponse(responseJson, successCallBack, failCallBack);
           } else {
               if (failCallBack && !this.isCancled) failCallBack('請求失敗');
           }
       } catch (erro) {
           if (this.isShowing) {
               this.dismissLoadingView();
           }
           this.showLog('erro==>');
           this.showLog(erro);
           if (failCallBack && !this.isCancled) failCallBack(erro);
       }
       return this;
   }

   /**
    * 處理response
    * @param responseJson
    * @param successCallBack
    */
   handleResponse(responseJson, successCallBack, failCallBack) {
       if (this.requestTime) {
           try {
               console.log('********requestUrl: ' + this.requestUrl());
               console.log('********This request consumes time: ' + (new Date().getTime() - this.startTime) + 'ms');
           } catch (e) {
           }
       }
       if (this.isShowing) {
           this.dismissLoadingView();
       }
       // 我們項目里面 code 為200 或者 '200' 作為網(wǎng)絡(luò)請求成功的標示 其余為失敗 大家可以根據(jù)自己項目的實際情況做更改
       if ('200' == responseJson.code || parseInt(responseJson.code) === 200) {
           if (successCallBack) successCallBack(responseJson);
       } else if (responseJson.message && responseJson.message.length > 0 && this.isShowMessage) {
           // 可以在這里利用 code 處理錯誤信息  例如:token失效 調(diào)用登陸
           // Alert(responseJson.message);
           if (failCallBack) failCallBack(responseJson);
       } else {
           if (failCallBack) failCallBack(responseJson);
       }
   }

   /**
    * 請求是否已取消
    * @returns {*|boolean}
    */
   isCancel() {
       return this.isCancled;
   }

   /**
    * 是否取消請求
    * @param cancle
    */
   setCancled(cancle) {
       this.isCancled = cancle;
       if (this.isShowing) {
           this.dismissLoadingView();
       }
   }

   /**
    * 請求失敗后是否顯示后臺message
    * @param show
    * @returns {BaseRequest}
    */
   setShowMessage(show) {
       this.isShowMessage = show;
       return this;
   }

   /**
    * 用于對對象編碼以便進行傳輸
    * @param obj 對象參數(shù)
    * @returns {string} 返回字符串
    */
   toQueryString(obj) {
       let str = '';
       if (obj) {
           let keys = [];
           for (let key in obj) {
               keys.push(key);
           }
           keys.forEach((key, index) => {
               str += key + '=' + obj[key];
               if (index !== keys.length - 1) {
                   str += '&';
               }
           });
       }
       return str;
   }

   /**
    * 打印后臺message
    * @param str
    */
   alertWithStr(str) {
       TimerMiXin.setTimeout(() => {
           if (Platform.OS == 'ios') {
               Alert.alert(
                   str,
                   null,
                   [
                       {text: '確定'}
                   ]
               );
           }
           if (Platform.OS == 'android') {
               // 彈窗  可以自己寫
           }
       }, 1000);
   }

   /**
    * 打印log信息
    * @param log
    */
   showLog(log) {
       if (DEBUG_MODE) {
           console.log(log);
       }
   }

   /**
    * 返回baseurl
    */
   getBaseUrl() {
       return baseUrl;
   }

   /**
    * 是否打印接口請求時間
    * @returns {boolean}
    */
   getDefaultTestingTime() {
       return false;
   }
}

如需擴展,添加一些功能,可以參考showLoadingView()。
如有錯誤,歡迎指正。等有時間我會寫個 demo 上傳到github。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容