1. 程式人生 > >angularjs http 請求 php 無資料解決辦法

angularjs http 請求 php 無資料解決辦法

雖然angularjs自帶http請求,但是當它的後臺為php時,我們往往拿不到想要的資料(相同的請求用jQuery能正確返回結果)。其實這是因為angularjs預設的請求方式不適合php接收而已。因此我們需要修改或者使用其他的請求方式來實現與後臺的互動。

$http預設請求頭資訊

$http服務將會給所有請求自動建立HTTP頭。這個預設設定能完全的通過訪問$httpProvider.defaults.headers配置物件配置。目前包含默:

  $httpProvider.defaults.headers.common
        //-- Accept:application/json,text/plain
  $httpProvider.defaults
.headers.post //-- Content-Type:application/json $httpProvider.defaults.headers.put //-- Content-Type:application/json

解決方法

以下案例均通過wampserver環境下的php後臺請求測試,如果非此類環境有可能拿不到想要的結果,請自行封裝其他方法解決。

以下案例的實現均需要有正常的php開發環境來支援,假如我們有這樣一個ajax.php檔案:

<?php
header('Content-type:text/html;charset=utf-8'
); if ($_GET) { $msg = ['name' => $_GET['name'], 'type' => '這是get請求']; echo json_encode($msg); exit(); } if ($_POST) { $msg = ['name' => $_POST['name'], 'type' => '這是post請求']; echo json_encode($msg); exit(); } $msg = ['type' => '這是其他請求']; echo json_encode($msg);

方法一:封裝自定義httpService服務(推薦做法)

利用$httpParamSerializerJQLike和Content-Type設定來封裝自定義服務,可以友好解決這個問題,而且它可以像jQuery那樣發請求(注意自定義服務的呼叫方式,如果不明白什麼是服務,可以參考angularjs service 自定義服務 或者 angularjs factory (工廠服務))。

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <title>angularjs service</title>
    <meta name="author" content="loushengyue">
</head>
<body>

<div ng-app="app" ng-controller="ctrl">
    <h1>請按F12檢視控制檯的console面板</h1>
</div>

<script src="https://cdn.bootcss.com/angular.js/1.6.9/angular.min.js"></script>
<script>
    angular.module('app', [])
            .controller('ctrl', ['$scope', 'httpService', function ($scope, httpService) {
                var option = {
                    type: 'post',
                    url: './ajax.php',
                    data: {
                        name: 'loushengyue'
                    }
                };
                httpService.request(option).then(function (res) {
                    console.log(res);
                }, function (error) {
                    console.log(error);
                })
            }])
            .service('httpService', ['$http', '$q', '$httpParamSerializerJQLike',
                function ($http, $q, $httpParamSerializerJQLike) {
                    //$httpParamSerializerJQLike表示它可以像jquery那樣序列化資料
                    this.request = function (option) {
                        if (!option || !option.url) {
                            throw new Error('option or option.url is undefind.');
                        }
                        var def = $q.defer(), _method,
                                _data = option.data ? option.data : {};
                        option.method = option.method ? option.method : (option.type ? option.type : 'get');
                        _method = angular.uppercase(option.method);
                        if (_method === 'GET' && !option.params) {
                            option.params = _data; //使get請求支援data傳參
                        }
                        if (_method === 'POST') {
                            var _config = {
                                headers: {"Content-Type": "application/x-www-form-urlencoded"}
                            };
                            option.data = $httpParamSerializerJQLike(_data);
                            angular.merge(option, _config);//合併請求引數使post請求類似jquery一樣
                        }
                        $http(option).then(function (res) {
                            def.resolve(res.data)
                        }, function (error) {
                            def.reject(error)
                        });
                        return def.promise;
                    };
                    return this;
                }])
</script>
</body>
</html>

方法二: 修改$httpProvider配製

這是一種各大部落格網友推薦的一種做法,它能夠一次性配製所有的$http內建服務的post請求方式(不過這種配製是有漏洞的,它不支援複雜引數的傳遞)。

<div ng-app="app" ng-controller="ctrl">
    <h1>請按F12檢視控制檯的console面板</h1>
    <div>
        <button ng-click="getRequest()">get request test</button>
        <br>
        <button ng-click="postRequest()">post request test</button>
    </div>
</div>

<script src="https://cdn.bootcss.com/angular.js/1.6.9/angular.min.js"></script>
<script>
    angular.module('app', [])
            .config(['$httpProvider', function ($httpProvider) {
                $httpProvider.defaults.transformRequest = function (data) {
                    var arr = [];
                    angular.forEach(data, function (val, key) {
                        arr.push(encodeURIComponent(key) + '=' + encodeURIComponent(val));
                    });
                    return arr.join('&');
                };
                //通過下面這一行你能看到你$http的預設配置資訊
                console.log($httpProvider.defaults.headers);//請自行刪除本行
                $httpProvider.defaults.headers = {
                    post: {
                        'Content-Type': 'application/x-www-form-urlencoded'
                    }
                }
            }])
            .controller('ctrl', ['$scope', '$http', function ($scope, $http) {
                $scope.getRequest = function () {
                    $http({
                        method: 'get',//切記這裡是method!!jQuery用的是type
                        url: './ajax.php?name=loushengyue&age=30'
                        //angularjs的get請求沒有data傳參,需要拼接url或者用params物件
                    }).then(function (res) {
                        console.log(res.data);
                        alert('get success')
                    })
                };
                $scope.postRequest = function () {
                    $http({
                        method: 'post', //切記這裡是method!!jQuery用的是type
                        url: './ajax.php',
                        data: {
                            name: 'loushengyue',
                            age: 30,
                            sex: 'male'
                        }
                    }).then(function (res) {
                        console.log(res.data);
                        alert('post success');
                    })
                };
            }])
</script>

方法三:修改$http配置

<div ng-app="app" ng-controller="ctrl">
    <h1>請按F12檢視控制檯的console面板</h1>
    <div>
        <button ng-click="getRequest()">get request test</button>
        <br>
        <button ng-click="postRequest()">post request test</button>
    </div>
</div>

<script src="https://cdn.bootcss.com/angular.js/1.6.9/angular.min.js"></script>
<script>
    angular.module('app', [])
            .controller('ctrl', ['$scope', '$http', '$httpParamSerializerJQLike',
                function ($scope, $http, $httpParamSerializerJQLike) {
                    $scope.getRequest = function () {
                        $http({
                            method: 'get',//切記這裡是method!!jQuery用的是type
                            url: './ajax.php',
                            params: {
                                name: 'test',
                                age: 18
                            }
                            //angularjs的get請求沒有data傳參,需要拼接url或者用params物件
                        }).then(function (res) {
                            console.log(res.data);
                            alert('get success')
                        })
                    };
                    $scope.postRequest = function () {
                        $http({
                            method: 'post', //切記這裡是method!!jQuery用的是type
                            url: './ajax.php',
                            data: $httpParamSerializerJQLike({
                                name: 'loushengyue',
                                age: 30,
                                sex: 'male'
                            }),
                            headers: {
                                'Content-Type': 'application/x-www-form-urlencoded'
                            }
                        }).then(function (res) {
                            console.log(res.data);
                            alert('post success');
                        })
                    };
                }])
</script>

$httpParamSerializerJQLike部分原碼展示

function jQueryLikeParamSerializer(params) {
        if (!params) return '';
        var parts = [];
        serialize(params, '', true);
        return parts.join('&');

        function serialize(toSerialize, prefix, topLevel) {
            if (toSerialize === null || isUndefined(toSerialize)) return;
            if (isArray(toSerialize)) {
                forEach(toSerialize, function (value, index) {
                    serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
                });
            } else if (isObject(toSerialize) && !isDate(toSerialize)) {
                forEachSorted(toSerialize, function (value, key) {
                    serialize(value, prefix +
                            (topLevel ? '' : '[') +
                            key +
                            (topLevel ? '' : ']'));
                });
            } else {
                parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
            }
        }
    }

    function encodeUriQuery(val, pctEncodeSpaces) {
        return encodeURIComponent(val).
        replace(/%40/gi, '@').
        replace(/%3A/gi, ':').
        replace(/%24/g, '$').
        replace(/%2C/gi, ',').
        replace(/%3B/gi, ';').
        replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
    }

      function serializeValue(v) {
        if (isObject(v)) {
            return isDate(v) ? v.toISOString() : toJson(v);
        }
        return v;
    }