欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

RN网络请求封装

程序员文章站 2022-06-05 21:06:52
...

前言

作为前端开发人员,网络请求工具对大家来说肯定不陌生。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) => {
    ...
});
...