Android Fetch请求问题

前言

作为前端开发人员,网络请求工具对大家来说肯定不陌生。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里面的属性。

问题一

在封装RN fetch请求时header设置如下:

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

但是在Android手机上发送POST接口请求时底层报错如下:

12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err: java.lang.IllegalArgumentException: multipart != application/json
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at okhttp3.MultipartBody$Builder.setType(MultipartBody.java:299)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.modules.network.NetworkingModule.constructMultipartBody(NetworkingModule.java:622)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.modules.network.NetworkingModule.sendRequest(NetworkingModule.java:410)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:374)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:162)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at android.os.Handler.handleCallback(Handler.java:743)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:95)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:31)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at android.os.Looper.loop(Looper.java:150)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.bridge.queue.MessageQueueThreadImpl$3.run(MessageQueueThreadImpl.java:194)
12-01 16:50:42.602 26135-26531/air.com.wuba.cardealertong W/System.err:     at java.lang.Thread.run(Thread.java:833)

查看RN Android底层源码看到 RN的fetch请求在Android底层Content-Type只支持multipart/form-data类型

但是iOS底层支持application/json、text/plain、application/x-www-form-urlencoded类型;不支持multipart/form-data

由于iOS对实体数据类型支持的格式不同需要分端处理header

if (Platform.OS == "ios") {
    header = {
        Accept: "application/json",
        "Content-Type": "application/json"
    };
} else {
    header = {
        "Content-Type": "multipart/form-data"
    };
}

问题二

POST请求封装如下:

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("当前网络不可用,请检查网络设置!");
        });
};

如果POST请求无需传参 此时FormData如下:

FormData {_parts: Array(0)}

Android底层会报错,错误如下:

12-01 17:47:11.440 4738-5202/air.com.wuba.cardealertong W/System.err: java.lang.IllegalStateException: Multipart body must have at least one part.
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at okhttp3.MultipartBody$Builder.build(MultipartBody.java:335)
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.modules.network.NetworkingModule.sendRequest(NetworkingModule.java:414)
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:374)
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:162)
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at android.os.Handler.handleCallback(Handler.java:743)
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:95)
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:31)
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at android.os.Looper.loop(Looper.java:150)
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at com.facebook.react.bridge.queue.MessageQueueThreadImpl$3.run(MessageQueueThreadImpl.java:194)
12-01 17:47:11.441 4738-5202/air.com.wuba.cardealertong W/System.err:     at java.lang.Thread.run(Thread.java:833)

处理方式:

前端兼容POST参数,如果POST请求无需传参 也就是params为空时,前端拼接一个空的part,part的key、value值都zhiwei空

let formData = new FormData();
if (WBCST.isEmptyOfObject(params)) {
    formData.append("", "");
} else {
    Object.keys(params).forEach((key) => formData.append(key, params[key]));
}

以上的兼容都在rn-app中封装网络请求时处理过了,如果不调用rn-app中的网络请求的话,需要自己注意以上的坑;建议大家使用时都调用封装处理好的网络请求:

GET请求:WBCST.getFetch

POST请求:WBCST.postFetch

具体使用详见 网络请求模块

猜你喜欢

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