前言
React Native可以使用多種方式來進行網絡請求,比如fetch、XMLHttpRequest以及基于它們封裝的框架,fetch可以說是替代XMLHttpRequest的產物,這一節我們就來學習fetch的基本用法。
1.get請求
fetch API是基于 Promise 設計的,因此了解Promise也是有必要的,推薦閱讀MDN Promise教程 。
get請求訪問淘寶IP庫
我們先從最基礎的get請求開始,get請求的地址為淘寶IP地址庫,里面有訪問接口的說明。請求代碼如下所示。
fetch('http://ip.taobao.com/service/getIpInfo.php?ip=59.108.51.32', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}).then((response) => {//1
console.log(response);
}).catch((err) => {//2
console.error(err);
});
其中method用于定義請求的方法,這里不用寫method也可以,fetch默認的method就是GET。fetch方法會返回一個Promise對象,這個Promise對象中包含了響應數據response,也就是注釋1處的response參數。在注釋1處調用then方法將response打印在控制臺Console中,then方法同樣也會返回Promise對象,Promise對象可以進行鏈式調用,這樣就可以通過多次調用then方法對響應數據進行處理。在注釋2處通過catch方法來處理請求網絡錯誤的情況。
除了上面這一種寫法,我們還可以使用Request,如下所示。
let request = new Request('http://liuwangshu.cn', {
method: 'GET',
headers: ({
'Content-Type': 'application/json'
})
});
fetch(request).then((response) => {
console.log(response);
}).catch((err) => {
console.error(err);
});
我們先創建了Request對象,并對它進行設置,最后交給fetch處理。
為了驗證fetch的get請求,需要添加觸發get請求的代碼邏輯,如下所示。
import React, {Component} from 'react';
import {AppRegistry, View, Text, StyleSheet, TouchableHighlight} from 'react-native';
class Fetch extends Component {
render() {
return (
<View style={styles.container}>
<TouchableHighlight
underlayColor='rgb(210,260,260)'
style={{padding: 10, marginTop: 10, borderRadius: 5,}}
onPress={this.get}
>
<Text >get請求</Text>
</TouchableHighlight>
</View>
);
}
get() {
fetch('http://ip.taobao.com/service/getIpInfo.php?ip=59.108.51.32', {
method: 'GET',
}).then((response) => {
console.log(response);//1
}).catch((err) => {//2
console.error(err);
});
}
}
const styles = StyleSheet.create({
container: {
alignItems: 'center',
}
});
AppRegistry.registerComponent('FetchSample', () => Fetch);
這里添加了一個TouchableHighlight,并定義了它的點擊事件,一旦點擊就會觸發get方法請求網絡。運行程序點擊“get請求”,這時在控制臺Console中就會顯示回調的Response對象的數據,它包含了響應狀態(status)、頭部信息(headers)、請求的url(url)、返回的數據等信息。這次請求的響應狀態status為200,返回的數據是JSON格式的,用Charles抓包來查看返回的JSON,如下圖所示。
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。
接下來對返回的Response進行簡單的數據處理,如下所示。
get() {
fetch('http://ip.taobao.com/service/getIpInfo.php?ip=59.108.23.12', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}).then((response) => response.json())//1
.then((jsonData) => {//2
let country = jsonData.data.country;
let city = jsonData.data.city;
alert("country:" + country + "-------city:" + city);
});
}
訪問淘寶IP地址庫會返回JSON數據,因此在注釋1處調用response的json方法,將response轉換成一個帶有JSON對象的Promise,也就是注釋2處的jsonData。最后取出jsonData中數據并展示在Alert中,這里data是一個對象,如果它是一個對象數組我們可以這樣獲取它的數據:
let country=jsonData.data[0].country;
點擊“get請求”,效果如下所示。
2.post請求
post請求的代碼如下所示。
post() {
fetch('http://ip.taobao.com/service/getIpInfo.php', {
method: 'POST',//1
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({//2
'ip': '59.108.23.12'
})
}).then((response) => response.json())
.then((jsonData) => {
let country = jsonData.data.country;
let city = jsonData.data.city;
alert("country:" + country + "-------city:" + city);
});
}
在注釋1處將method改為POST,在注釋2處添加請求的body。與get請求類似,這里也添加一個觸發事件來進行post請求,當點擊“post請求”時,查看Charles抓包的請求的信息,如下圖所示。
可以看到請求數據是一個GSON字符串,因為淘寶IP庫并不支持此類型的POST請求,所以不會返回我們需要的地理信息數據。
3.簡單封裝fetch
如果每次請求網絡都要設定method、headers、body等數據,同時還要多次調用then方法對返回數據進行處理,顯然很麻煩,下面就對上面例子中的get和post請求做一個簡單的封裝。
首先創建一個FetchUtils.js,代碼如下所示。
import React, {Component} from 'react';
class FetchUtils extends React.Component {
static send(method, url, data, callback) {
let request;
if (method === 'get') {
request = new Request(url, {
method: 'GET',
headers: ({
'Content-Type': 'application/json'
})
});
} else if (method === 'post') {
request = new Request(url, {
method: 'POST',
headers: ({
'Content-Type': 'application/json'
}),
body: JSON.stringify(data)
});
}
fetch(request).then((response) => response.json())
.then((jsonData) => {
callback(jsonData);//1
});
}
}
module.exports = FetchUtils;
在FetchUtils中定義了send方法,對GET和POST請求做了區分處理,并在注釋1處通過callback將響應數據response回調給調用者。
最后調用FetchUtils的send方法,分別進行GET和POST請求:
let FetchUtils=require('./FetchUtils');
...
sendGet() {
FetchUtils.send('get', 'http://ip.taobao.com/service/getIpInfo.php?ip=59.108.23.16', '',
jsonData => {
let country = jsonData.data.country;
let city = jsonData.data.city;
alert("country:" + country + "-------city:" + city);
})
}
sendPost() {
FetchUtils.send('post', 'http://ip.taobao.com/service/getIpInfo.php', {'ip': '59.108.23.16'},
jsonData => {
let country = jsonData.data.country;
let city = jsonData.data.city;
alert("country:" + country + "-------city:" + city);
})
}
這樣我們使用Fetch訪問網絡時,只需要傳入需要的參數,并對返回的jsonData 進行處理就可以了。
參考資料
Fetch API
fetch-issues-274
MDN Promise教程
ReactNative網絡fetch數據并展示在listview中
React Native中的網絡請求fetch和簡單封裝
在 JS 中使用 fetch 更加高效地進行網絡請求
Using Fetch
歡迎關注我的微信公眾號,第一時間獲得博客更新提醒,以及更多成體系的Android相關原創技術干貨。
掃一掃下方二維碼或者長按識別二維碼,即可關注。