React Native提供了和web标准一致的Fetch API,用于满足开发者访问网络的需求 React Native中已经内置了XMLHttpRequest API(也就是俗称的ajax)。一些基于XMLHttpRequest封装的第三方库也可以使用,例如frisbee或是axios等。
Request 基于fetch 的 Promise 流程:
请求发起 -> 网络判断 -> 超时处理 -> 响应状态判断 -> Promise result
网络判断:
const isBadNetwork = await NetInfo.getConnectionInfo().then(({ type }) => {
if (type === 'none' || type === 'unknown') {
return true;
} else {
return false;
}
});
超时处理: Promise.race + setTimeout
const timeoutFetch = (api, options) => {
const fetchPromise = fetch(HOST + api, options);
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error(CODE_MESSAGE.timeOut)), TIMEOUT);
});
return Promise.race([fetchPromise, timeoutPromise]);
};
响应状态判断: status >= 200 && res.status < 300
const checkHttpStatus = (res) => {
if (res.status >= 200 && res.status < 300) {
return res;
}
throw new Error(CODE_MESSAGE.http[res.status] || res.statusText);
};
异步结果:
return Promise.resolve(result);
import NetInfo from "@react-native-community/netinfo";
import Toast from 'react-native-root-toast';
import { HOST } from '~/contants/Config';
import { CODE_MESSAGE } from '~/contants/Common';
const TIMEOUT = 20 * 1000;
// 对象转请求字符串 id=2&name='xxx'
const stringParams = obj =>
Object.keys(obj)
.reduce((acc, cur) => acc.concat([[cur, obj[cur]].join('=')]), [])
.join('&');
const GET = (api, params = {}) => {
const options = {
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
};
const str = stringParams(params);
const url = str.length > 0 ? `${api}?${str}` : api;
return request(url, options);
};
const POST = (api, params = {}) => {
const options = {
method: 'POST',
body: JSON.stringify(params),
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
};
return request(api, options);
};
// 提示
const toastHandler = msg => Toast.show(msg, { position: Toast.positions.CENTER });
// 响应状态判断
const checkHttpStatus = (res) => {
if (res.status >= 200 && res.status < 300) {
return res;
}
throw new Error(CODE_MESSAGE.http[res.status] || res.statusText);
};
// 超时
const timeoutFetch = (api, options) => {
const fetchPromise = fetch(HOST + api, options);
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error(CODE_MESSAGE.timeOut)), TIMEOUT);
});
return Promise.race([fetchPromise, timeoutPromise]);
};
const request = async (api, options) => {
const isBadNetwork = await NetInfo.getConnectionInfo().then(({ type }) => {
if (type === 'none' || type === 'unknown') {
return true;
} else {
return false;
}
});
if (isBadNetwork) {
toastHandler(CODE_MESSAGE.networkError);
} else {
const result = await timeoutFetch(api, options)
.then(res => checkHttpStatus(res, api, options))
.then(res => res.json())
.catch(err => {
toastHandler(err.message);
// console.error('request failed: ', err.message, api, options);
});
if (result) {
const { code, msg } = result;
if (code !== 200) {
toastHandler(msg);
return Promise.reject(result);
}
return Promise.resolve(result);
}
}
};
export default {
GET,
POST
}