React Native探索(五)使用fetch進行網絡請求

前言

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抓包的請求的信息,如下圖所示。

QQ圖片20170606135823.jpg

可以看到請求數據是一個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 進行處理就可以了。

github源碼

參考資料
Fetch API
fetch-issues-274
MDN Promise教程
ReactNative網絡fetch數據并展示在listview中
React Native中的網絡請求fetch和簡單封裝
在 JS 中使用 fetch 更加高效地進行網絡請求
Using Fetch


歡迎關注我的微信公眾號,第一時間獲得博客更新提醒,以及更多成體系的Android相關原創技術干貨。
掃一掃下方二維碼或者長按識別二維碼,即可關注。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容