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

NiZerin發表於2020-02-25

前言

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://iacblog.com', {
            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,如下圖所示。
VYsHXT.jpg

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請求”,效果如下所示。
VYsqnU.jpg

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

VYs7cV.jpg

可以看到請求資料是一個 JSON 字串,因為淘寶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 進行處理就可以了。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

By: Laravel-China 寧澤林
MyBlog: nizer.in

相關文章