ReactNative碎片整理之网络请求

React Native 中虽然也内置了XMLHttpRequest 网络请求Api(也就是ajax),但XMLHttpRequest 是一个设计粗糙的API,不符合职责分离的原则,配置和调用方式比较混乱,而且基于事件的异步模型不如现代的Promise友好。所以,React Native官方推荐使用Fetch Api

Fetch基本使用

最简单的使用

如果只是请求一下服务器,不需要任何操作

1
fetch('http://chenxiaoping.com/demo')添加请求头

添加请求头和请求参数(服务端支持json参数)

1
2
3
4
5
6
7
8
9
10
11
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
})

添加请求头和请求参数(服务端不支持json参数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'key1=value1&key2=value2'
})
//或者
let formData = new FormData();
formData.append('username', String(phone));
formData.append('password', String(password));
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: formData
})

Response对象参数解析

Response对象中包含了多种属性:

  • status (number) : HTTP请求的响应状态行。
  • statusText (String) : 服务器返回的状态报告。
  • ok (boolean) :如果返回200表示请求成功,则为true。
  • headers (Headers) : 返回头部信息。
  • url (String) :请求的地址。

Response对象还提供了多种方法:

  • formData():返回一个带有FormData的Promise。
  • json() :返回一个带有JSON对象的Promise。
  • text():返回一个带有文本的Promise。
  • clone() :复制一份response。
  • error():返回一个与网络相关的错误。
  • redirect():返回了一个可以重定向至某URL的response。
  • arrayBuffer():返回一个带有ArrayBuffer的Promise。
  • blob() : 返回一个带有Blob的Promise。

解析json和修改json数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
loadData() {
return fetch('https://facebook.github.io/react-native/movies.json',)
.then((response) => response.json())
.then((json) => {
json['description']='hello'
Alert.alert(json.description)
})
.catch((error) => {
this.setState(() => {
return {
buttonText: 'doLoad',
}
});
console.error(error);
})
}

response:

1
2
3
4
5
6
7
8
9
10
11
{
"title": "The Basics - Networking",
"description": "Your app fetched this from a remote endpoint!",
"movies": [
{ "id": "1", "title": "Star Wars", "releaseYear": "1977" },
{ "id": "2", "title": "Back to the Future", "releaseYear": "1985" },
{ "id": "3", "title": "The Matrix", "releaseYear": "1999" },
{ "id": "4", "title": "Inception", "releaseYear": "2010" },
{ "id": "5", "title": "Interstellar", "releaseYear": "2014" }
]
}

可以看到弹窗为‘hello’

超时

1
fetch(input, init).then(function(response) { ... });

参数

  • input

定义要获取的资源。这可能是: 一个 USVString 字符串,包含要获取资源的 URL。 一个 Request 对象。

  • init 可选 一个配置项对象,包括所有对请求的设置。可选的参数有:
  1. method: 请求使用的方法,如 GET、POST。
  2. headers: 请求的头信息,形式为 Headers 对象或 ByteString。 body: 请求的 body 信息:可能是一个 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
  3. mode: 请求的模式,如 cors、 no-cors 或者 same-origin。
  4. credentials: 请求的 credentials,如 omit、same-origin 或者 include。
  5. cache: 请求的 cache 模式: default, no-store, reload, no-cache, force-cache, or only-if-cached.

根本找不到 timeout 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 超时版的fetch
_fetch(fetch, timeout) {
return Promise.race([
fetch,
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), timeout);
})
]);
}
// 使用
_fetch(fetch('url'), 1000).then((info)=> {
return info.text();
}).then((info)=> {
console.log(info);
}).catch((err)=> {
throw new Error(err);
});

代码中用Promise.race()将fetch和一个新的Promise包装在了一起,新的Promise和fetch谁率先返回就把该Promise实例返回值传递给下面的.then()或者是.catch()

让fetch也可以timeout

可以设置超时版的的fetch

fetch添加超时时间只需几行代码–fetch timeout

简单封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//封装的请求  带超时
const _timeout = 30*1000 //默认30秒
//GET请求
const GET=(url, version, timeout = _timeout)=> {
var dispatchTimeout = null;
var timeoutPromise = new Promise((resolve, reject) => {
dispatchTimeout = () => {
reject('请求超时')
}
})
setTimeout(() => {
dispatchTimeout();
}, timeout);

var getPromise = new Promise((resolve, reject) => {
fetch(url, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
// 'api-version': version,
},
})
.then((response) => response.json())
.then((responseData) => {
resolve(responseData)
})
.catch((error) => {
reject(error);
})
})
return Promise.race([getPromise,timeoutPromise]);
}
//POST请求
const POST=(url, version, body, timeout = _timeout) =>{

let dispatchTimeout = null;
let timeoutPromise = new Promise((resolve, reject) => {
dispatchTimeout = () => {
reject('请求超时')
}
})
setTimeout(() => {
dispatchTimeout();
}, timeout);

let postPromise = new Promise((resolve, reject) => {
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
// 'Content-Type': 'application/json',
// 'api-version': version,
},
// body: 'username=fengan&password=123456',
// body: JSON.stringify(body),
body: body,
})
.then((response) => response.json())
.then((responseData) => {
resolve(responseData)
})
.catch((error) => {
reject(error)
});
})

return Promise.race([postPromise,timeoutPromise]);
}

export { GET, POST }

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
export default class FetchUtil {
init() {
this.url = '';
this.method = 'GET';
this.headers = {};
this.body_type = 'form';
this.bodys = {};
this.credentials = 'omit';
//默认返回json对象
this.return_type = 'json';
this.overtime = 0;
this.firstThen = undefined;

return this;
}
setUrl(url) {
this.url = url;
return this;
}
setMethod(val) {
this.method = val;
return this;
}
setBodyType(val) {
this.body_type = val;
return this;
}

setReturnType(val) {
this.return_type = val;
return this;
}

setOvertime(val) {
this.overtime = val;
return this;
}

setHeader(name, val = null) {
if (typeof name == 'string') {
this.headers[name] = val;
} else if (typeof name == 'object') {
Object.keys(name).map((index) => {
this.headers[index] = name[index];
});
}

return this;
}

setBody(name, val = null) {
if (typeof name == 'string') {
this.bodys[name] = val;
} else if (typeof name == 'object') {
Object.keys(name).map((index) => {
this.bodys[index] = name[index];
});
}
return this;
}

setCookieOrigin() {
this.credentials = 'same-origin';
return this;
}

setCookieCors() {
this.credentials = 'include';
return this;
}

thenStart(then) {
this.firstThen = then;
return this;
}

dofetch() {
let options = {};
options.method = this.method;
options.credentials = this.credentials;

options.headers = this.headers;

if ({} != this.bodys && this.method != 'GET') {
if ('form' == this.body_type) {
this.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
let data = '';
Object.keys(this.bodys).map((index) => {
let param = encodeURI(this.bodys[index]);
data += `${index}=${param}&`;
});
options.body = data;
} else if ('file' == this.body_type) {
let data = new FormData();
Object.keys(this.bodys).map((index) => {
data.append(index, this.bodys[index]);
});
options.body = data;
} else if ('json' == this.body_type) {
options.body = JSON.stringify(this.bodys);
}
}

return Promise.race([
fetch(this.url, options),
new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('request timeout')), this.overtime ? this.overtime : 30 * 1000);
})
]).then(
(response) => {
if (this.firstThen) {
let tempResponse = this.firstThen(response);
if (tempResponse) {
return tempResponse;
}
}
return response;
}
).then(
(response) => {
if ('json' == this.return_type) {
return response.json();
} else if ('text' == this.return_type) {
return response.text();
} else if ('blob' == this.return_type) {
return response.blob();
} else if ('formData' == this.return_type) {
return response.formData();
} else if ('arrayBuffer' == this.return_type) {
return response.arrayBuffer();
}
}
);
}
}

//use
let fetchUtil = new FetchUtil();
fetchUtil.init()
.setUrl('https://www.google.com/')
.setMethod('GET')
.setOvertime(15 * 1000)
.setHeader({
'Accept': 'application/json',
'Content-Type': 'application/json'
})
.dofetch()
.then((response) => {
//这里的response已经被转成object了
console.warn( typeof response.title);
})
.then((data) => {

Alert.alert(data);
})
.catch((error) => {
console.warn( '=> catch: ', error);
// console.log('=> catch: ', error);
});
文章目录
  1. 1. Fetch基本使用
    1. 1.1. 最简单的使用
  2. 2. Response对象参数解析
  3. 3. 超时
  4. 4. 参数
  5. 5. 简单封装