fetch('http://nero-zou.com/test', {
method: 'GET'
}).then(function(response) {
//获取数据,数据处理
}).catch(function(err) {
//错误处理
});
let param = {user:'xxx',phone:'xxxxxx'};
fetch(url, {
method: 'post',
body: JSON.stringify(param)
}).then(function(response) {
//获取数据,数据处理
});
try {
fetch(url, {
method: 'post',
body: JSON.stringify(param)
}).then(function(response) {
//获取数据,数据处理
});
} catch(e) {
//捕获异常消息
}
fetch(url, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', },
body: JSON.stringify({ firstParam: 'yourValue', secondParam: 'yourOtherValue', })
})
基本上要求是写个基础的函数,其它在进行网络请求时都调用这个函数。即使以后不使用fetch 直接将这个基础函数修改,不用修改其它的地方就可以实现。
基础函数的模型一般是这样的
function sendNetRequest(...props) {
this.url = props.shift(1);
this.options = props.shift(1);
return fetch(this.url, Object.assign({}, this.options))
.then((response) =>return response.json());
}
封装各个接口
//封装login 接口
function postLogin(userName,password) {
let loginParam= {user:userName,password:password};
var loginApiPort = "mlogin";//login 对应的接口
//下面的baseURL=https://XXXXX.com
return sendNetRequest(`${baseURL}/${loginApiPort}`, {
method: 'post',
body: JSON.stringify(loginParam),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
}
//...其它一系列接口的封装
调用实例
try {
postLogin(user,password)
.then((response) => { //获取数据,数据处理 }) } catch(e) { //捕获异常消息 }
这样就大功告成了,下面是遇到的常见问题
将header里面的Content-Type 设置为’application/x-www-form-urlencoded’,如果还是报错问server 端参数是什么格式 ,然后设置Content-Type的值即可.
上述封装容易出现的问题在 response.json() 这一句中,如果response==null就会抛出异常,建议先判断response是否为null,如果为null 再进行特殊处理。
fetch 本身目前没有设置超时时间的属性,只能机制来进行设置。fetch函数在各个平台的实现,如果你看到源代码的话肯定会觉得能设置超时而且很容易,但是它封装的时候并没有把 这个作为一个属性来设置.因此只能结合promise 机制使用setTimeout 来设置超时的时间。
SSLHandshake: Received fatal alert: certificate_expired
或者是
SSLHandshake: Remote host closed connection during handshake
…
其他rn版本的文件目录可以推测,总的来说是修改reactnative的network库里面的OkHttpClientProvider.java 这个文件。
OkHttpClientProvider.java 中找到下述代码
return new OkHttpClient.Builder()
.connectTimeout(0, TimeUnit.MILLISECONDS)
.readTimeout(0, TimeUnit.MILLISECONDS)
.writeTimeout(0, TimeUnit.MILLISECONDS)
.cookieJar(new ReactCookieJarContainer())
.build();
改为:
return new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory())
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true; //忽略所有的认证,直接返回了true
}
})
.connectTimeout(0, TimeUnit.MILLISECONDS)
.readTimeout(0, TimeUnit.MILLISECONDS)
.writeTimeout(0, TimeUnit.MILLISECONDS)
.cookieJar(new ReactCookieJarContainer())
.build();
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
肯定还是报错 ,找到React native 的networking 库,在库里面添加 NSURLSession delegate 函数处理ssl 证书认证的相关代码,设置为都为pass,你可以根据是否是debug模式 来选择是不是pass ,如果是release 版建议不要这样做。
如这个函数
//根据你自己的逻辑处理这个函数,加点判断千万别直接pass,有安全隐患,如果都pass了还不如用http省的麻烦。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
react native 的网络操作常用的是 fetch,经了解fetch 函数的实现在iOS 和android 平台上各自都是使用RCTNetworking 实现的。
上述第4个问题的解决就是通过看RCTNetworking源代码来解决的。
以下是实现的RCTNetworking ,仔细看是用OkHttpClient来实现的。
@ReactModule(name = "RCTNetworking", supportsWebWorkers = true)
public final class NetworkingModule extends ReactContextBaseJavaModule {
private static final String CONTENT_ENCODING_HEADER_NAME = "content-encoding";
private static final String CONTENT_TYPE_HEADER_NAME = "content-type";
private static final String REQUEST_BODY_KEY_STRING = "string";
private static final String REQUEST_BODY_KEY_URI = "uri";
private static final String REQUEST_BODY_KEY_FORMDATA = "formData";
private static final String USER_AGENT_HEADER_NAME = "user-agent";
private static final int CHUNK_TIMEOUT_NS = 100 * 1000000; // 100ms
private static final int MAX_CHUNK_SIZE_BETWEEN_FLUSHES = 8 * 1024; // 8K
private final OkHttpClient mClient;//其实内部是使用的OkHttpClient
private final ForwardingCookieHandler mCookieHandler;
private final @Nullable String mDefaultUserAgent;
private final CookieJarContainer mCookieJarContainer;
private final Set<Integer> mRequestIds;
private boolean mShuttingDown;
/* package */ NetworkingModule(
ReactApplicationContext reactContext,
@Nullable String defaultUserAgent,
OkHttpClient client,
@Nullable List<NetworkInterceptorCreator> networkInterceptorCreators) {
super(reactContext);
if (networkInterceptorCreators != null) {
OkHttpClient.Builder clientBuilder = client.newBuilder();
for (NetworkInterceptorCreator networkInterceptorCreator : networkInterceptorCreators) {
clientBuilder.addNetworkInterceptor(networkInterceptorCreator.create());
}
client = clientBuilder.build();
}
mClient = client;
OkHttpClientProvider.replaceOkHttpClient(client);
mCookieHandler = new ForwardingCookieHandler(reactContext);
mCookieJarContainer = (CookieJarContainer) mClient.cookieJar();
mShuttingDown = false;
mDefaultUserAgent = defaultUserAgent;
mRequestIds = new HashSet<>();
}
public class OkHttpClientProvider {
// Centralized OkHttpClient for all networking requests.
private static @Nullable OkHttpClient sClient;
public static OkHttpClient getOkHttpClient() {
if (sClient == null) {
//sClient = createClient();
sClient=createClient_initNetworkConfig();
}
return sClient;
}
// okhttp3 OkHttpClient is immutable
// This allows app to init an OkHttpClient with custom settings.
public static void replaceOkHttpClient(OkHttpClient client) {
sClient = client;
}
private static OkHttpClient createClient() {
// No timeouts by default
return new OkHttpClient.Builder()
.connectTimeout(0, TimeUnit.MILLISECONDS)
.readTimeout(0, TimeUnit.MILLISECONDS)
.writeTimeout(0, TimeUnit.MILLISECONDS)
.cookieJar(new ReactCookieJarContainer())
.build();
}
通过上述代码你可以发现超时可以设置,但是fetch 没有封装该属性。
RCTNetInfo 类实现的功能:查询是否联网 是否是WiFi 。
RCTNetworking类实现的功能:跟AFNetworking的实现差不多,你可以仔细研究一下。
暂时略。
执行命令react-native init ZXJNetDemo
新建文件BaseServiceApiNet.js:
const baseURL = "https://api.app.net";
function fetchAction(...props) {
this.url = props.shift(1);
this.options = props.shift(1);
return fetch(this.url, Object.assign({}, this.options))
.then((response) =>response.json());
}
export default {
getTest() {
var apiPort = "stream/0/posts/stream/global";
return fetchAction(`${baseURL}/${apiPort}`, {
method: 'get',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
}
};
文件index.ios.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
ActivityIndicator
} from 'react-native';
import BaseServiceApiNet from './BaseServiceApiNet';
export default class ZXJNetDemo extends Component {
constructor(props){
super(props);
this.state ={
isLoading:false,
resultJson:null
};
}
sendTestRequest(){
if(this.state.isLoading==true){
return;
}
this.setState({
resultJson:null,
isLoading:true
});
try {
BaseServiceApiNet.getTest()
.then((response) => { let data = response.meta; this.setState({ resultJson:data==null?null:JSON.stringify(data), isLoading:false }); console.log("返回数据:"+JSON.stringify(data)); }) } catch(e) { alert(e); this.setState({ isLoading:false }); } } render() { return ( <View style={styles.container}> <ActivityIndicator animating={this.state.isLoading} /> <Text style={styles.welcome} onPress={this.sendTestRequest.bind(this)}> 测试网络 </Text> <Text style={styles.instructions}> {this.state.resultJson} </Text> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, }); AppRegistry.registerComponent('ZXJNetDemo', () => ZXJNetDemo);