AngularJS HTTP发布到PHP,并且未定义


107

我有一个带有标签的表格 ng-submit="login()

该函数在javascript中被称为罚款。

function LoginForm($scope, $http)
{
    $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';

    $scope.email    = "fsdg@sdf.com";
    $scope.password = "1234";

    $scope.login = function()
    {
        data = {
            'email' : $scope.email,
            'password' : $scope.password
        };

        $http.post('resources/curl.php', data)
        .success(function(data, status, headers, config)
        {
            console.log(status + ' - ' + data);
        })
        .error(function(data, status, headers, config)
        {
            console.log('error');
        });
    }
}

我从PHP文件中获得了200 OK响应,但是返回的数据就是这样,email并且password未定义。这就是我拥有的所有php

<?php
$email = $_POST['email'];
$pass  = $_POST['password'];
echo $email;
?>

知道为什么我会得到未定义的POST值吗?

编辑

我想指出,因为这似乎是一个受欢迎的问题(但它是旧的),.success.error已被弃用,你应该使用.then如@詹姆斯氏族在commments指出


2
您是否在查看开发人员工具的“网络”标签?传入什么值$http
Marcel Korpel 2013年

1
在“网络”标签下的Form-Data{"email":"fsdg@sdf.com","password":"1234"}
Ronnie

@Ronnie好像是JSON。尝试print_r($_POST);然后尝试json_decode()正确的索引
HamZa 2013年

1
echo 'test';工作良好。我当然指的是对的文件
罗尼

1
请注意,不赞成使用.success和.error并将其替换为.thendocs.angularjs.org/api/ng/service/$http
James Gentes

Answers:


228

angularjs .post()默认将Content-type标头设置为application/json。您要覆盖此内容以传递表单编码的数据,但是您没有更改您的data值以传递适当的查询字符串,因此未填充PHP$_POST按预期。

我的建议是只使用默认的angularjs设置 application/json作为标头,读取PHP中的原始输入,然后反序列化JSON。

可以这样在PHP中实现:

$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
$email = $request->email;
$pass = $request->password;

或者,如果您严重依赖$_POST功能,则可以形成类似的查询字符串email=someemail@email.com&password=somepassword并将其作为数据发送。确保此查询字符串是URL编码的。如果是手动构建的(而不是使用类似的东西jQuery.serialize()),则Javascript encodeURIComponent()可以为您解决问题。


7
不尊重您的知识,但是使用file_get_contents("php://input");似乎有点像黑客,不是吗?我从来没有听说过这个。需要发生什么,所以我可以参考一下$_POST['email'];
罗尼

6
@Ronnie这不是黑客。这实际上取决于您要如何设置Web服务。如果要发送和检索JSON,则需要处理原始输入,因为$_POST不会填充原始输入。
Mike Brant

1
@lepe我不清楚链接的问题/答案与我的答案之间的关系。这里没有讨论需要序列化javascript对象的讨论。
Mike Brant

2
@lascort实际上与解决方案之间并没有太大区别。在我的解决方案中,我没有将数据填充到$ _POST中,而是使用了用户定义的变量。总的来说,这对我来说更有意义,因为在处理JSON序列化数据时,您可能正在使用对象或数字索引数组。我不建议在$ _POST中添加一个数字索引数组,因为这将是非典型的用法。我通常也避免将数据放入用于输入数据的任何超全局变量中。
Mike Brant

1
@ItsmeJulian没有绝对正确的答案。这可能实际上取决于您的应用程序的架构。如果您正在与使用/提供JSON的REST服务进行交互,那么我可能会坚持使用JSON内容类型。如果我主要使用端点,则可以生成HTML或HTML片段,或者使用基本的表单发布作为AJAX的后备,那么我可能会倾向于使用表单编码。
Mike Brant

41

我是在服务器端,在我的init文件开始的时候做的,就像一个超级按钮,您不必在angular或现有的php代码中做任何事情:

if ($_SERVER['REQUEST_METHOD'] == 'POST' && empty($_POST))
    $_POST = json_decode(file_get_contents('php://input'), true);

3
如果$ _POST为空,则应该转换结果$_POST = (array) json_decode(file_get_contents('php://input'), true)
M'sieur Toph'14/

我真的不明白为什么PHP的人不会自己实现这一点,他们真的希望始终使用url编码的帖子吗?
azerafati 2015年

@Bludream我不明白为什么有人期望PHP可以完成预期的工作。它始终违反最小惊讶原则。
doug65536

除非您完全知道POSTED数据表示关联数组(JSON中的对象表示),否则这似乎是一种非常脆弱的方法。如果JSON包含数字索引数组表示形式怎么办? $_POST在这种情况下,最终将得到一个数字索引数组,这在依赖一致的$_POST超全局行为的系统其他部分中将是非常意外的行为。
Mike Brant 2015年

1
当然,我只在有角度的应用程序中使用它,并且我非常彻底地验证了我的POST数据,看不出这怎么可能是个问题...
valmarv 2015年

14

在我正在开发的API中,我有一个基本控制器,在它的__construct()方法中,我有以下内容:

if(isset($_SERVER["CONTENT_TYPE"]) && strpos($_SERVER["CONTENT_TYPE"], "application/json") !== false) {
    $_POST = array_merge($_POST, (array) json_decode(trim(file_get_contents('php://input')), true));
}

这使我可以在需要时将json数据简单地引用为$ _POST [“ var”]。效果很好。

这样,如果经过身份验证的用户连接到诸如jQuery之类的库,该库发送默认值为Content-Type:application / x-www-form-urlencoded或Content-Type:application / json的帖子数据,则该API将响应而不会出现错误,并且会使API对开发人员更加友好。

希望这可以帮助。


11

因为PHP本身不接受JSON 'application/json'一种方法是从angular更新标题和参数,以便您的api可以直接使用数据。

首先,参数化您的数据:

data: $.param({ "foo": $scope.fooValue })

然后,将以下内容添加到$http

 headers: {
     'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8'
 }, 

如果所有请求都发送给PHP,则可以在配置中全局设置参数,如下所示:

myApp.config(function($httpProvider) {
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
});

8

Angular Js演示代码:-

angular.module('ModuleName',[]).controller('main', ['$http', function($http){

                var formData = { password: 'test pwd', email : 'test email' };
                var postData = 'myData='+JSON.stringify(formData);
                $http({
                        method : 'POST',
                        url : 'resources/curl.php',
                        data: postData,
                        headers : {'Content-Type': 'application/x-www-form-urlencoded'}  

                }).success(function(res){
                        console.log(res);
                }).error(function(error){
                        console.log(error);
        });

        }]);

服务器端代码:-

<?php


// it will print whole json string, which you access after json_decocde in php
$myData = json_decode($_POST['myData']);
print_r($myData);

?>

由于角度行为,PHP服务器上没有用于正常发布行为的直接方法,因此您必须在json对象中进行管理。


1
这是不正确的。请参阅上面的答案,其中直接从PHP原始输入读取JSON。这比将JSON混合到查询字符串中要简单得多。
Mike Brant

.success.error方法已过时,从AngularJS框架已被删除。
georgeawg '19

6

您需要先反序列化表单数据,然后再将其作为第二个参数传递给.post()。您可以使用jQuery的$ .param(数据)方法来实现。然后,您将可以在服务器端像$ .POST ['email'];一样引用它。


6

这是最佳解决方案(IMO),因为它不需要jQuery,也不需要JSON解码:

来源:https : //wordpress.stackexchange.com/a/179373 和:https : //stackoverflow.com/a/1714899/196507

摘要:

//Replacement of jQuery.param
var serialize = function(obj, prefix) {
  var str = [];
  for(var p in obj) {
    if (obj.hasOwnProperty(p)) {
      var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
      str.push(typeof v == "object" ?
        serialize(v, k) :
        encodeURIComponent(k) + "=" + encodeURIComponent(v));
    }
  }
  return str.join("&");
};

//Your AngularJS application:
var app = angular.module('foo', []);

app.config(function ($httpProvider) {
    // send all requests payload as query string
    $httpProvider.defaults.transformRequest = function(data){
        if (data === undefined) {
            return data;
        }
        return serialize(data);
    };

    // set all post requests content type
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
});

例:

...
   var data = { id: 'some_id', name : 'some_name' };
   $http.post(my_php_url,data).success(function(data){
        // It works!
   }).error(function() {
        // :(
   });

PHP代码:

<?php
    $id = $_POST["id"];
?>

关于:JSON.stringify('{ id: 'some_id', name : 'some_name' }')还是$httpParamSerializer用于客户端转换?
qrtLs

5

这是一个古老的问题,但值得一提的是,在Angular 1.4中添加了$ httpParamSerializer,并且在使用$ http.post时,如果我们使用$ httpParamSerializer(params)传递参数,则所有内容都将像常规的post请求一样工作,并且不进行JSON反序列化在服务器端需要。

https://docs.angularjs.org/api/ng/service/$httpParamSerializer


1

在使用Angular和PHP时,我花了几个小时才能理解。发布数据不会在$ _POST中发送到PHP

在PHP代码中执行以下操作。-创建变量$ angular_post_params-然后执行以下操作 $angular_http_params = (array)json_decode(trim(file_get_contents('php://input')));

现在您可以像从$ _POST一样访问参数

$angular_http_params["key"]

如果您想了解javascript ....这就是我用的

    var myApp = angular.module('appUsers', []);
    //var post_params = $.param({ request_type: "getListOfUsersWithRolesInfo" });
    var dataObj = {
        task_to_perform: 'getListOfUsersWithRolesInfo'
    };

    myApp.controller('ctrlListOfUsers', function ($scope, $http) {
        $http({
            method: 'POST',
            dataType: 'json',
            url: ajax_processor_url,
            headers: {
                'Content-Type': 'application/json'
            },
            data: dataObj,
            //transformRequest: function(){},
            timeout: 30000,
            cache: false
        }).
        success(function (rsp) {
            console.log("success");
            console.log(rsp);
        }).
        error(function (rsp) {
            console.log("error");
        });
    });

对于新手...不要忘记在页面上的内容所有者容器中添加了ng-app和ng-controller指令:)
Talha

.success.error方法已过时,从AngularJS框架已被删除。
georgeawg,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.