RN网络请求封装

前言

作为前端开发人员,网络请求工具对大家来说肯定不陌生。iOS的AFNetworking,Android的okHttp等。但是对于RN来说,我们最常用到的就是js原生的Fetch请求了。

React Native提供了和web标准一致的Fetch API,用于满足开发者访问网络的需求。如果你之前使用过XMLHttpRequest(即俗称的ajax)或是其他的网络API,那么Fetch用起来将会相当容易上手。这篇文档只会列出Fetch的基本用法,并不会讲述太多细节,你可以使用你喜欢的搜索引擎去搜索fetch api关键字以了解更多信息。

fetch请求的格式

fetch使用链式调用的方式来进行操作,fetch的基本格式

fetch(url , fetchOptions)
    .then((response) => {
        ...//数据解析方式
    })
    .then((responseData) => {
        ...//获取到的数据处理
    })
    .catch((error) => {
        ...//错误处理
    })
    .done(); //结束链式

fetch(url)为发起网络请求的最简单的写法,只传入一个参数,默认的为GET方式请求,将网址作为参数传入fetch 的方法,如:

fetch('https://mywebsite.com/mydata.json')

fetch还有可选的第二个参数,即示例中的fetchOptions,是一个对象,对象中包含如下属性

let fetchOptions = {
    method:'POST',
    headers:{
        'Accept':'application/json',
        'Content-Type':'application/json',
    },
    body:JSON.stringify({
        firstParam:'yourValue',
        secondParam:'yourOtherValue',
    })
};

fetch(url , fetchOptions);
  • method:网络请求的方式(GET、POST等)
  • headers:网络请求的请求头对象,对象中包含(Accept、Content-Type、token等属性)
  • body:POST请求的请求体对象,即需要往服务器发送的数据
  • mode:跨域设置(cors, no-cors, same-origin) 不常用
  • cache:缓存选项(default, no-store, reload, no-cache, force-cache, or only-if-cached)不常用
参数解释

1、headers请求头遵循http协议规范,通常设置Accept、Content-Type属性。
Accept:希望接受的数据类型
Content-Type:发送的实体数据的数据类型

headers: {
    'Accept' : 'application/json',
    'Content-Type' : 'application/json',
}

2、body的传入参数有三种方式:
方式一:不推荐,可能在某些服务器无法识别。

JSON.stringify({key:value1 , key2:value2 , ...})

方式二:传统的form格式

'key1 = value1 & key2 = value2'

方式三:使用FormData

let formData = new FormData();
formData.append("key1" , "value1");
formData.append("key2" , "value2");

3、mode:控制属否允许跨域:

  • same-origin: 同源请求,该模式是不允许跨域的,跨域回报error。
  • cors: 允许跨域请求,可以获取第三方数据,前提是所访问的服务允许跨域访问。
  • no-cors:默认mode。该模式允许发送本次跨域请求,但是不能访问响应返回的内容,即可以请求其他域的脚本、图片和其他资源,但是不能访问response里面的属性。

fetch轻量级封装

fetch封装源码核心 HttpUtils.js

/**
 * Created by gongchenghui on 2018/4/19.
 */

/** 基于fetch 封装的网络请求工具类 **/

import { Component } from "react";

/**
 * fetch 网络请求的header,可自定义header 内容
 * @type {{Accept: string, Content-Type: string, accessToken: *}}
 */
let header = {
    Accept: "application/json",
    "Content-Type": "application/json"
};

/**
 * GET 请求时,拼接请求URL
 * @param url 请求URL
 * @param params 请求参数
 * @returns {*}
 */
const handleUrl = (url) => (params) => {
    if (params) {
        let paramsArray = [];
        Object.keys(params).forEach((key) =>
            paramsArray.push(key + "=" + encodeURIComponent(params[key]))
        );
        if (url.search(/\?/) === -1) {
            typeof params === "object" ? (url += "?" + paramsArray.join("&")) : url;
        } else {
            url += "&" + paramsArray.join("&");
        }
    }
    return url;
};

/**
 * fetch 网络请求超时处理
 * @param original_promise 原始的fetch
 * @param timeout 超时时间 30s
 * @returns {Promise.<*>}
 */
const timeoutFetch = (originalFetch, timeout = 30000) => {
    let timeoutBlock = () => {};
    let timeoutPromise = new Promise((resolve, reject) => {
        timeoutBlock = () => {
            // 请求超时处理
            reject("timeout promise");
        };
    });

    // Promise.race(iterable)方法返回一个promise
    // 这个promise在iterable中的任意一个promise被解决或拒绝后,立刻以相同的解决值被解决或以相同的拒绝原因被拒绝。
    let abortablePromise = Promise.race([originalFetch, timeoutPromise]);

    setTimeout(() => {
        timeoutBlock();
    }, timeout);

    return abortablePromise;
};

/**
 * 网络请求工具类
 */
export default class HttpUtils extends Component {
    /**
     * 基于fetch 封装的GET 网络请求
     * @param url 请求URL
     * @param params 请求参数
     * @returns {Promise}
     */
    static getRequest = (url, params = {}) => {
        return timeoutFetch(
            fetch(handleUrl(url)(params), {
                method: "GET",
                headers: header
            })
        )
            .then((response) => {
                if (response.ok) {
                    return response.json();
                } else {
                    // alert("服务器繁忙,请稍后再试!");
                }
            })
            .then((response) => {
                // response.code:是与服务器端约定code:200表示请求成功,非200表示请求失败,message:请求失败内容
                if (response) {
                    return response;
                } else {
                    // 非 200,错误处理
                    return response;
                }
            })
            .catch((error) => {});
    };

    /**
     * 基于fetch 的 POST 请求
     * @param url 请求的URL
     * @param params 请求参数
     * @returns {Promise}
     */
    static postRequrst = (url, params = {}) => {
        let formData = new FormData();
        Object.keys(params).forEach((key) => formData.append(key, params[key]));
        return timeoutFetch(
            fetch(url, {
                method: "POST",
                headers: header,
                body: formData
            })
        )
            .then((response) => {
                if (response.ok) {
                    return response.json();
                } else {
                    // alert("服务器繁忙,请稍后再试;\r\nCode:" + response.status);
                }
            })
            .then((response) => {
                // response.code:是与服务器端约定code:200表示请求成功,非200表示请求失败,message:请求失败内容
                if (response && response.code === 200) {
                    return response;
                } else {
                    return response;
                }
            })
            .catch((error) => {
                // alert("当前网络不可用,请检查网络设置!");
            });
    };
}

方法输出 HttpExtension.js:

/**
 * Created by gongchenghui on 2018/4/19.
 */

/** 网络请求工具类的拓展类,便于后期网络层修改维护 **/

import HttpUtils from "./HttpUtils";
import { dataCache } from "../cache";

// const API_URL = "https://api-m.mtime.cn";
// const API_URL = "http://apimanage.58corp.com/";

/**
 * GET
 * 从缓存中读取数据
 * @param isCache: 是否缓存
 * @param url 请求url
 * @param params 请求参数
 * @param isCache 是否缓存
 * @param callback 是否有回调函数
 * @returns {value\promise}
 * 返回的值如果从缓存中取到数据就直接换行数据,或则返回promise对象
 */
const fetchData = (isCache, type) => (url, params, callback) => {
    url = `${url}`;
    // url = `${API_URL}${url}`;

    const fetchFunc = () => {
        let promise =
            type === "get" ? HttpUtils.getRequest(url, params) : HttpUtils.postRequrst(url, params);
        if (callback && typeof callback === "function") {
            promise.then((response) => {
                return callback(response);
            });
        }
        return promise;
    };

    return dataCache(url, fetchFunc, isCache);
};

/**
 * GET 请求
 * @param url
 * @param params
 * @param source
 * @param callback
 * @returns {{promise: Promise}}
 */
const getFetch = fetchData(false, "get");

/**
 * POST 请求
 * @param url
 * @param params
 * @param callback
 * @returns {{promise: Promise}}
 */
const postFetch = fetchData(false, "post");

/**
 * GET 请求,带缓存策略
 * @param url
 * @param params
 * @param callback
 * @returns {{promise: Promise}}
 */
const getFetchFromCache = fetchData(true, "get");

export { getFetch, postFetch, getFetchFromCache };

缓存设置:

/**
 * FetchNetworkDemo
 * Created by gongchenghui on 2018/4/19
 */

import store from "react-native-simple-store";

/**
 * @param key:key为url的Path
 * @param fetchFunc:回调函数
 * @param isCache:是否需要缓存
 * @returns {value}
 */
const dataCache = (key, fetchFunc, isCache) => {
    // 不缓存,
    if (!isCache) {
        return fetchFunc();
    }
    // 需要缓存
    return store.get(key).then((value) => {
        if (value) {
            // 如果在缓存中找到数据,则返回缓存中的数据
            return value;
        } else {
            // 如果在缓存中取不到数据,则从网络请求中获取数据,并将获取到的数据缓存下来
            return fetchFunc().then((value) => {
                value ? store.save(key, value) : null;
                return value;
            });
        }
    });
};

export { dataCache };

使用:

import WEBAPP from "@/"import WEBAPP from "@/"

...
WEBAPP.getFetch(url, param).then((response) => {
    ...
});
WEBAPP.postFetch(url, param).then((response) => {
    ...
});
...

猜你喜欢

转载自blog.csdn.net/gongch0604/article/details/84630587