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

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

是的,Android WebView 支持 Fetch API。WebView 是 Android 平台上的一个组件,用于在应用程序中显示网页内容。它是基于 Chromium 的,因此支持许多现代的 web 标准和 API,包括 Fetch API。 您可以在 WebView 中使用 Fetch API 发送网络请求,获取数据并进行处理。以下是一个简单的示例: ```java // 创建 WebView 实例 WebView webView = new WebView(context); // 启用 JavaScript WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); // 在 WebView 中加载网页 webView.loadUrl("https://www.example.com"); // 设置 WebView 的 WebViewClient webView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); // 在页面加载完成后,使用 Fetch API 发送请求 view.evaluateJavascript("fetch('https://api.example.com/data')" + ".then(response => response.json())" + ".then(data => {" + " // 处理返回的数据" + " console.log(data);" + "})" + ".catch(error => {" + " // 处理错误" + " console.error(error);" + "});", null); } }); ``` 在上面的示例中,我们创建了一个 WebView 实例,并启用了 JavaScript 功能。然后,我们加载了一个网页,并在页面加载完成后使用 `evaluateJavascript` 方法来执行 JavaScript 代码,其中包括使用 Fetch API 发送请求和处理返回的数据的逻辑。 请注意,为了使用 Fetch API,您需要确保在 WebView 中启用了 JavaScript。另外,您还可以通过设置 WebViewClient 来处理页面加载和其他事件。这只是一个简单的示例,您可以根据您的具体需求进行自定义和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值