導語
在項目開發(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。