AngularJs $http.post()方法未发送数据。

343

有人能告诉我为什么以下语句不能将POST数据发送到指定的URL吗?该URL已被调用,但在服务器上打印$ _POST时,我得到了一个空数组。如果我在添加数据之前将消息打印到控制台中,则会显示正确的内容。

$http.post('request-url',  { 'message' : message });

我也尝试使用字符串数据(结果相同):

$http.post('request-url',  "message=" + message);

当我使用以下格式时,它似乎正在工作:

$http({
    method: 'POST',
    url: 'request-url',
    data: "message=" + message,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});

但是是否可以使用$http.post()的方式来实现呢?我是否必须始终包含头信息才能使其工作?我相信上述的内容类型指定了发送数据的格式,但我是否可以将其作为JavaScript对象发送?


URL是否在同一来源? - fmquaglia
抱歉 - 对于所有示例,它们都是相同的URL。 - Spencer Mark
@SpencerMark 抱歉..我尝试了你的代码,但对我来说不起作用。 - Arul Sidthan
37个回答

347

我在使用asp.net MVC时遇到了同样的问题,在这里找到了解决方案

对于新手来说,AngularJS中的$http服务简写函数($http.post()等)与jQuery中的等效函数(jQuery.post()等)为什么不可交换存在很多困惑。

区别在于jQueryAngularJS序列化和传输数据的方式。 从根本上讲,问题在于您选择的服务器语言无法本地理解AngularJS的传输... 默认情况下,jQuery使用

Content-Type: x-www-form-urlencoded

并且熟悉的 foo=bar&baz=moe 序列化。

然而,AngularJS 使用以下方式传输数据

Content-Type: application/json 

{ "foo": "bar", "baz": "moe" }

JSON序列化,不幸的是一些Web服务器语言(尤其是PHP)不能原生反序列化。

非常好用。

CODE

// Your app's root module...
angular.module('MyModule', [], function($httpProvider) {
  // Use x-www-form-urlencoded Content-Type
  $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
 
  /**
   * The workhorse; converts an object to x-www-form-urlencoded serialization.
   * @param {Object} obj
   * @return {String}
   */ 
  var param = function(obj) {
    var query = '', name, value, fullSubName, subName, subValue, innerObj, i;
      
    for(name in obj) {
      value = obj[name];
        
      if(value instanceof Array) {
        for(i=0; i<value.length; ++i) {
          subValue = value[i];
          fullSubName = name + '[' + i + ']';
          innerObj = {};
          innerObj[fullSubName] = subValue;
          query += param(innerObj) + '&';
        }
      }
      else if(value instanceof Object) {
        for(subName in value) {
          subValue = value[subName];
          fullSubName = name + '[' + subName + ']';
          innerObj = {};
          innerObj[fullSubName] = subValue;
          query += param(innerObj) + '&';
        }
      }
      else if(value !== undefined && value !== null)
        query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
    }
      
    return query.length ? query.substr(0, query.length - 1) : query;
  };
 
  // Override $http service's default transformRequest
  $httpProvider.defaults.transformRequest = [function(data) {
    return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;
  }];
});

7
我已将该脚本添加到 Bower 上,使用 bower install angular-post-fix --save-dev 命令即可安装。 - Billy Blaze
那么有没有办法更改PHP的数据传输方法呢?因为这是我目前遇到的问题。 - Demodave
1
这段代码大部分情况下都能正常工作,但是当提交一组空对象的层次结构或者仅仅是扁平的空值时,我遇到了问题。例如,{ a: 1, b: { c: { d: { } } }, e: undefined, f: null, g: 2 } 将无法正确编码,PHP将把它视为 [ "a" => "1", "g" => "2" ]。整个 "b" 下的结构,以及 "e" 和 "f",包括键本身 - 都会丢失。我在下面发布了替代代码,使用它可以将上述结构解码为:[ "a" => "1", "b" => [ "c" => [ "d" => "" ] ], "e" => "", "f" => "", "g" => "2" ]。 - obe
1
我应该如何为multipart/form-data实现这个? - davidlee
我仍然认为客户端无法知道服务器正在理解哪个表单消息,无论是Content-Type:x-www-form-urlencoded还是Content-Type:application/json。 - xpioneer
显示剩余4条评论

116

上面的内容不是非常清晰,但如果您在PHP中收到请求,可以使用以下方法:

$params = json_decode(file_get_contents('php://input'),true);

从AngularJS POST访问PHP数组。


3
当用json_decode(file_get_contents('php://input'), true)覆盖$_POST数组时,我需要添加true参数使其强制转换为数组。 - Jon
4
@Zalaboza,我同意很难有任何被认为是“普遍适用”的解决方案,但我不同意这是“hacky”的—— php.net指出:“file_get_contents()是将文件内容读入字符串的首选方式。如果您的操作系统支持内存映射技术,则它将使用此技术来提高性能。”当然,我们在这种情况下没有读取文件,但我们仍然需要读取已发布的JSON数据。如果您能贡献一个新答案或提供新信息来帮助读者(包括我自己)做出更好的决定,那就太好了。 - Don F

78

您可以像这样设置默认的“Content-Type”:

$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";

关于 data 格式:

$http.post 和 $http.put 方法的 data 参数接受任何 JavaScript 对象(或字符串)值。如果 data 是一个 JavaScript 对象,它默认会被转换成 JSON 字符串。

尝试使用这种变化

function sendData($scope) {
    $http({
        url: 'request-url',
        method: "POST",
        data: { 'message' : message }
    })
    .then(function(response) {
            // success
    }, 
    function(response) { // optional
            // failed
    });
}

10
似乎不起作用。我刚尝试了将数据作为字符串并添加以下标头的变体:{'Content-Type': 'application/x-www-form-urlencoded'} - 这似乎有效,但是否有更好的方法? - Spencer Mark
2
将默认内容类型设置为上述所述,并且对于数据,请勿使用js对象。使用类似这样的字符串:'message='+message 对我来说可行。 - gSorry

62

我遇到了类似的问题,我想知道这个链接是否也有用:https://dev59.com/SWgu5IYBdhLWcg3wRlL0#11443066

var xsrf = $.param({fkey: "key"});
$http({
    method: 'POST',
    url: url,
    data: xsrf,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})

敬礼,


看起来头信息是我们唯一需要更改的地方。谢谢! - Ben Guthrie
谢谢,这对我有帮助 :) 问题是POST数据的编码。 - Daan

34

我喜欢使用一个函数将对象转换为 POST 参数。

myobject = {'one':'1','two':'2','three':'3'}

Object.toparams = function ObjecttoParams(obj) {
    var p = [];
    for (var key in obj) {
        p.push(key + '=' + encodeURIComponent(obj[key]));
    }
    return p.join('&');
};

$http({
    method: 'POST',
    url: url,
    data: Object.toparams(myobject),
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})

30

使用$httpParamSerializerJQLike,在angular 1.4中终于解决了这个问题。

详见https://github.com/angular/angular.js/issues/6039

.controller('myCtrl', function($http, $httpParamSerializerJQLike) {
$http({
  method: 'POST',
  url: baseUrl,
  data: $httpParamSerializerJQLike({
    "user":{
      "email":"wahxxx@gmail.com",
      "password":"123456"
    }
  }),
  headers:
    'Content-Type': 'application/x-www-form-urlencoded'
})})

我遇到了问题 POST http://192.168.225.75:7788/procure/p/search 400 (错误的请求) - Anuj

20

我使用jQuery paramAngularJS post请求。这是一个例子...创建AngularJS应用程序模块,其中myapp在你的HTML代码中使用ng-app定义。

var app = angular.module('myapp', []);

现在让我们创建一个登录控制器并POST电子邮件和密码。

app.controller('LoginController', ['$scope', '$http', function ($scope, $http) {
    // default post header
    $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
    // send login data
    $http({
        method: 'POST',
        url: 'https://example.com/user/login',
        data: $.param({
            email: $scope.email,
            password: $scope.password
        }),
        headers: {'Content-Type': 'application/x-www-form-urlencoded'}
    }).success(function (data, status, headers, config) {
        // handle success things
    }).error(function (data, status, headers, config) {
        // handle error things
    });
}]);

我不喜欢解释代码,它足够简单易懂 :) 请注意,param 来自 jQuery,因此您必须安装jQuery和AngularJS才能使其工作。这是一个屏幕截图。

enter image description here

希望这对您有所帮助。谢谢!


10

我在使用AngularJS和Node.js + Express 4 + Router时遇到了同样的问题。

Router期望从post请求中的body获取数据。如果我按照Angular文档的示例进行操作,这个body始终为空。

注1:

$http.post('/someUrl', {msg:'hello word!'})

但如果我在数据中使用它

符号2

$http({
       withCredentials: false,
       method: 'post',
       url: yourUrl,
       headers: {'Content-Type': 'application/x-www-form-urlencoded'},
       data: postData
 });

编辑1:

否则,如果使用符号1,则node.js路由器将期望在req.body中找到数据。

req.body.msg

还会将信息作为JSON有效负载发送。在JSON中有数组的情况下,这种方式更好,而x-www-form-urlencoded会出现一些问题。

它起作用了。希望能帮到你。


10

与jQuery不同,出于严谨性考虑,Angular使用JSON格式将客户端到服务器的POST数据进行传输(尽管JQuery和Angular都使用JSON进行数据输入,而JQuery应用x-www-form-urlencoded)。因此,问题分为两个部分:js客户端部分和服务器部分。因此,您需要:

  1. 像这样放置js Angular客户端部分:

  2. $http({
    method: 'POST',
    url: 'request-url',
    data: {'message': 'Hello world'}
    });
    

AND(逻辑运算符)

  1. 如果您使用的是 PHP ,则在服务器端编写代码来接收客户端发送的数据。

        $data               = file_get_contents("php://input");
        $dataJsonDecode     = json_decode($data);
        $message            = $dataJsonDecode->message;
        echo $message;     //'Hello world'

注意:$_POST将不起作用!

这个解决方案对我来说很好,希望对你也有帮助。


8

继@felipe-miosso的回答之后,我们可以有更多的发展:

  1. Download it as an AngularJS module from here,
  2. Install it
  3. Add it to your application:

    var app = angular.module('my_app', [ ... , 'httpPostFix']);
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接