前言
作为前端开发人员,网络请求工具对大家来说肯定不陌生。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
具体使用详见 网络请求模块