1. 程式人生 > >React Native 採用Fetch方式傳送跨域POST請求

React Native 採用Fetch方式傳送跨域POST請求

Fetch以後是趨勢,勢必要取代傳統的Ajax,而且RN框架支援Fetch。下面僅做了一個跨域請求的例子,在本域請求是一樣的,而且更簡單一些。客戶端環境用的是RN寫的一個頁面,也可以用瀏覽器的console控制檯模擬。後端服務用的是NodeJs express框架。

  

1)Fetch請求

//傳送Ajax請求
    sendAjax(){
        //POST方式,IP為本機IP
        fetch("http://192.168.111.102:8085", {
            method: "POST",
            mode: "cors",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            body: 'key=1'
        }).then(function (res) {
            console.log("fetch request ", JSON.stringify(res.ok));
            if(res.ok){
                res.json().then(function (json) {
                    console.info(json);
                    Alert.alert('提示','來自後臺數據:名字'+json.name+'、年齡'+json.age,[{text: '確定', onPress: () => console.log('OK Pressed!')},]);
                });
            }else{
                Alert.alert('提示','請求失敗',[{text: '確定', onPress: () => console.log('OK Pressed!')},]);
            }

        }).catch(function (e) {
            console.log("fetch fail");
            Alert.alert('提示','系統錯誤',[{text: '確定', onPress: () => console.log('OK Pressed!')},]);
        });
    }

1、mode屬性控制是否允許跨域。same-origin(同源請求)、no-cors(預設)和cros(允許跨域請求),第一種跨域求情會報error,第二種可以請求其他域的指令碼、圖片和其他資源,但是不能訪問response裡面的屬性,第三種可以獲取第三方資料,前提是所訪問的服務允許跨域訪問。否則,會出現如下錯誤:

 

2、Fetch請求後臺時,返回時一個Promise物件。物件支援解析返回資料的方法有:arrayBuffer()、blob()、formData()、json()、text()。

3、Body傳入引數,注意!注意!注意!重要的事情說三次,只能傳啊a=1&b=2...這種引數形式,不可傳物件{a:1,b:2,...},用JSON.stringify({a:1,b:2,...})也不行。在jquery中,傳入物件框架會自動封裝成formData的形式,fetch沒有這個功能。

4、使用時請注意瀏覽器版本,低版本不支援此物件。RN是可以用的

2)Nodejs express框架開啟允許跨域請求:
//設定跨域訪問
app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By",' 3.2.1');
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});
3)Nodejs express框架開啟處理POST資料功能,預設POST請求的引數是在請求體裡面,用res.query是獲取不到的,為{};需要使用res.body獲取,前提是要在express框架裡面開啟body解析功能,否則顯示undefined。
var express = require('express');
//Post方式請求引數放在請求體裡面,需引用body-parser解析body
var bodyParser = require("body-parser");
var app = express();

// 引用
app.use(bodyParser.urlencoded({ extended: false }));
4)支援jsonp方式跨域訪問,開啟跨域訪問後用傳統的jsonp方式請求時,會報錯。因為jsonp請求需要返回一個callback包裹的資料,否則解析出錯。此處有一個坑,用$.ajax({method:POST,dataType:jsonp})方式請求時,依然傳送的是GET請求。
//json資料
var  data  =   { "name":   "Test",   "age":   "19" };

app.get('/', function(req, res) {
    console.log('get..........');
    console.log(req.query);
    if (req.query && req.query.callback) {
        var str = req.query.callback + "(" + JSON.stringify(data) + ")"; //jsonp  
        console.log('jsonp: '+str);
        res.end(str);
    }else{
        console.log('json: '+JSON.stringify(data));
        res.end(JSON.stringify(data));
    }
});
5)完整程式碼:

1、RN前端

/**
 * Created by linyufeng on 2016/8/22.
 */

import React, { Component } from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    TouchableHighlight,
    Alert,
    View
} from 'react-native';

class HelloWorld extends Component {
//傳送Ajax請求
    sendAjax(){
        //POST方式
        fetch("http://192.168.111.102:8085", {
            method: "POST",
            mode: "cors",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            body: 'key=1'
        }).then(function (res) {
            console.log("fetch request ", JSON.stringify(res.ok));
            if(res.ok){
                res.json().then(function (json) {
                    console.info(json);
                    Alert.alert('提示','來自後臺數據:名字'+json.name+'、年齡'+json.age,[{text: '確定', onPress: () => console.log('OK Pressed!')},]);
                });
            }else{
                Alert.alert('提示','請求失敗',[{text: '確定', onPress: () => console.log('OK Pressed!')},]);
            }

        }).catch(function (e) {
            console.log("fetch fail");
            Alert.alert('提示','系統錯誤',[{text: '確定', onPress: () => console.log('OK Pressed!')},]);
        });
    }
    render() {
        return (
            點擊發送Ajax請求
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
    },
    wrapper: {
        borderRadius: 5,
        marginBottom: 5,
    },
    button: {
        backgroundColor: '#eeeeee',
        padding: 10,
    },
});

AppRegistry.registerComponent('HelloWorld', () => HelloWorld);
2、NodeJs
/**
 * Created by linyufeng on 2016/8/22.
 */

var express = require('express');
//Post方式請求引數放在請求體裡面,需引用body-parser解析body
var bodyParser = require("body-parser");
var app = express();

// 引用
app.use(bodyParser.urlencoded({ extended: false }));

//設定跨域訪問
app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By",' 3.2.1');
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});

//json資料
var data = { "name": "Test", "age": "19" };

app.get('/', function(req, res) {
    console.log('get..........');
    console.log(req.query);
    if (req.query && req.query.callback) {
        var str = req.query.callback + "(" + JSON.stringify(data) + ")"; //jsonp  
        console.log('jsonp: '+str);
        res.end(str);
    }else{
        console.log('json: '+JSON.stringify(data));
        res.end(JSON.stringify(data));
    }
});

app.post('/', function(req, res) {
    console.log('post............');
    console.log(req.body);
    console.log('json: '+JSON.stringify(data));
    res.end(JSON.stringify(data));
});

app.listen(8085, function () {
    console.log('Listening on port 8085...');
});