导语
在项目开发中,常用的工具类,我们都会专门封装起来进行统一处理,方便以后统一调用、修改。网络请求类算是用到最多的公共类之一了,本文就简单来对 react native 的 fetch 进行简单的封装,并不会讲述太多细节,你可以使用你喜欢的搜索引擎去搜索 fetch api 关键字以了解更多信息。
参考
fetch api
- method: 默认为 GET 请求
- headers:请求头 用来添加一些设备信息和用户信息
- body:请求体 请求参数
基本功能
- 支持 GET POST 两种请求 默认为 POST 请求
- 支持自定义请求头、传入请求参数
- 支持自定义请求超时时间
- 支持请求中断(防止重复发送同一个请求)
- 便于扩展
接下来先看一下我们的网络请求调用方式
第一步:创建,继承封装好的 fetch 类 重写一下 requestUrl 方法
class XXXRequest extends BaseRequest{
requestUrl() {
return 'api/xxx.xxx';
}
第二步:使用
//创建一个请求对象,参数为(请求体,请求方法)
XXXRequest request = new XXXRequest();
// timeout 超时时间 单位为 s
// 显示网络请求加载动画
request.timeout(10).showLoadingView().start(
// 成功的回调
(success)=>{
},
// 失败的的回调
(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 {
// 构造
constructor(body, method, mode) {
// 是否终止请求 默认false
this.isCancled = false;
// 请求失败是否打印后台message 默认false
this.isShowMessage = false;
if (body == null) {
body = {};
}
// 默认的一些参数比如 版本号 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',
// 在这里可以添加你需要添加的请求头参数
// 如 用户 token、手机设备号等等
};
// 扩展 网络请求耗时
this.requestTime = this.getDefaultTestingTime();
// 默认超时时间
// 想要超时时间生效 必须修改 fetch 的源码 在发请求之前加上如下代码 (路径为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 去控制显示加载
* 可以在这里面添加调用加载动画的代码
* @returns {BaseRequest}
*/
showLoadingView() {
this.isShowing = true;
// 没有删除自己的 redux
//store.dispatch(DialogAction.showLoading(true))
return this;
}
/**
* 关闭dialog
* @returns {BaseRequest}
*/
dismissLoadingView() {
this.isShowing = false;
// store.dispatch(DialogAction.showLoading(false))
return this;
}
/**
* 设置超时时间 如果不设置默认20s
*/
timeout(timeout) {
this.requestTimeout = typeof timeout === 'number' ? (timeout > 0 ? timeout : TIMEOUT) : TIMEOUT ;
return this;
}
/**
* 开始请求
* @param successCallBack 成功后的回调
* @param failCallBack 失败后的回调
* @returns {BaseRequest}
*/
start(successCallBack, failCallBack) {
//接口响应时间测试
if (this.requestTime) {
this.startTime = new Date().getTime();
}
//监听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 成功后的回调
* @param failCallBack 失败后的回调
* @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' 作为网络请求成功的标示 其余为失败 大家可以根据自己项目的实际情况做更改
if ('200' == responseJson.code || parseInt(responseJson.code) === 200) {
if (successCallBack) successCallBack(responseJson);
} else if (responseJson.message && responseJson.message.length > 0 && this.isShowMessage) {
// 可以在这里利用 code 处理错误信息 例如:token失效 调用登陆
// 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 对象参数
* @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。