首页 文章

AngularJs $ http.post()不发送数据

提问于
浏览
325

谁能告诉我为什么以下声明不会将发布数据发送到指定的网址?当我打印$ _POST时,在服务器上调用url - 我得到一个空数组 . 如果我在将数据添加到数据之前在控制台中打印消息 - 它会显示正确的内容 .

$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()来做 - 并且我总是必须包含 Headers 才能使它工作?我相信上面的内容类型是指定发送数据的格式,但我可以将其作为javascript对象发送吗?

30 回答

  • 6

    我喜欢使用函数将对象转换为post params .

    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'}
    })
    
  • 55

    使用asp.net MVC和found the solution here我遇到了同样的问题

    AngularJS的新手之间存在很多混淆,为什么$ http服务速记函数($ http.post()等)似乎不能与jQuery等价物交换(jQuery.post()等)不同之处在于jQuery和AngularJS如何序列化和传输数据 . 从根本上说,问题在于您选择的服务器语言本身无法理解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;
      }];
    });
    
  • 3

    上面不是很清楚,但如果您在PHP中收到请求,您可以使用:

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

    从AngularJS POST访问PHP中的数组 .

  • 7

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

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

    关于 data 格式:

    $ http.post和$ http.put方法接受任何JavaScript对象(或字符串)值作为其数据参数 . 如果data是JavaScript对象,则默认情况下它将转换为JSON字符串 .

    尝试使用此变体

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

    我有一个类似的问题,我想知道这是否也有用:https://stackoverflow.com/a/11443066

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

    问候,

  • 77

    最终使用 $httpParamSerializerJQLike 在角度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'
    })})
    
  • 2

    我使用jQuery paramAngularJS post requrest . 下面是一个示例...创建AngularJS应用程序模块,其中 myapp 在HTML代码中使用 ng-app 定义 .

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

    现在让我们创建一个Login控制器和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

    希望这是有帮助的 . 谢谢!

  • 3

    我在AngularJS和Node.js Express 4路由器上遇到了同样的问题

    路由器期望来自帖子请求的数据在正文中 . 如果我按照Angular Docs的例子,这个主体总是空的

    符号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:

    否则node.js路由器将使用req.body中的数据(如果使用符号1):

    req.body.msg
    

    其中还将信息作为JSON有效负载发送 . 在json和x-www-form-urlencoded中有数组的某些情况下,这会更好 .

    有效 . 希望能帮助到你 .

  • 8

    与JQuery不同,为了迂回曲折,Angular使用JSON格式从客户端到服务器的POST数据传输(JQuery应用x-www-form-urlencoded,尽管JQuery和Angular使用JSON进行数据输入) . 因此有两个问题:js客户端部分和服务器部分 . 所以你需要:

    • 把js Angular客户端部分放到这样:
    $http({
    method: 'POST',
    url: 'request-url',
    data: {'message': 'Hello world'}
    });
    

    AND

    • 在服务器部分写入以从客户端接收数据(如果是php) .
    $data               = file_get_contents("php://input");
            $dataJsonDecode     = json_decode($data);
            $message            = $dataJsonDecode->message;
            echo $message;     //'Hello world'
    

    注意:$ _POST不起作用!

    解决方案对我来说很好,希望和你 .

  • 3

    要使用 $http of angularjs通过Post方法发送数据,您需要更改

    data: "message=" + message ,与 data: $.param({message:message})

  • 9

    Build @ felipe-miosso的答案:

    • here下载为AngularJS模块,

    • 安装它

    • 将其添加到您的应用程序:

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

    我没有评论的声誉,但作为对Don F答案的回应/补充:

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

    第二个参数需要将 true 添加到 json_decode 函数中才能正确返回关联数组:

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

  • 32

    var payload = $.param({ jobId: 2 });
    
                    this.$http({
                        method: 'POST',
                        url: 'web/api/ResourceAction/processfile',
                        data: payload,
                        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
                    });
    

    WebAPI 2

    public class AcceptJobParams
            {
                public int jobId { get; set; }
            }
    
            public IHttpActionResult ProcessFile([FromBody]AcceptJobParams thing)
            {
                // do something with fileName parameter
    
                return Ok();
            }
    
  • 3

    这段代码为我解决了这个问题 . 它是一个应用程序级解决方案:

    moduleName.config(['$httpProvider',
      function($httpProvider) {
        $httpProvider.defaults.transformRequest.push(function(data) {
            var requestStr;
            if (data) {
                data = JSON.parse(data);
                for (var key in data) {
                    if (requestStr) {
                        requestStr += "&" + key + "=" + data[key];
                    } else {
                        requestStr = key + "=" + data[key];
                    }
                }
            }
            return requestStr;
        });
        $httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
      }
    ]);
    
  • 1

    在你的js文件中添加:

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

    并将其添加到您的服务器文件:

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

    这应该工作 .

  • 2

    我也面临类似的问题,我正在做这样的事情,但没有奏效 . 我的Spring控制器无法读取数据参数 .

    var paramsVal={data:'"id":"1"'};
      $http.post("Request URL",  {params: paramsVal});
    

    但是阅读这个论坛和API Doc,我尝试了以下方式,这对我有用 . 如果有人也有类似的问题,你也可以尝试以下方式 .

    $http({
          method: 'POST',
          url: "Request URL",           
          params: paramsVal,
          headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'}
                });
    

    请查看https://docs.angularjs.org/api/ng/service/ $ http#post以了解param配置的功能 . {data:' 1328090 : 1328091 '} - 将转换为URL的字符串或对象的映射?data = "id:1"

  • 4

    这可能是一个迟到的答案,但我认为最合适的方法是在使用"get"请求时使用相同的代码角度使用 $httpParamSerializer 将必须将其注入您的控制器,因此您可以简单地执行以下操作而无需使用Jquery, $http.post(url,$httpParamSerializer({param:val}))

    app.controller('ctrl',function($scope,$http,$httpParamSerializer){
        $http.post(url,$httpParamSerializer({param:val,secondParam:secondVal}));
    }
    
  • 29

    在我的情况下,我解决这个问题:

    var deferred = $q.defer();
    
    $http({
        method: 'POST',
        url: 'myUri', 
        data: $.param({ param1: 'blablabla', param2: JSON.stringify(objJSON) }),
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
    }).then(
        function(res) {
            console.log('succes !', res.data);
            deferred.resolve(res.data);
        },
        function(err) {
            console.log('error...', err);
            deferred.resolve(err);
        }
    );
    return deferred.promise;
    

    您需要为包含JSON对象的每个param使用JSON.stringify,然后使用“$ .param”构建数据对象:-)

    注意:我的“objJSON”是一个包含数组,整数,字符串和html内容的JSON对象 . 他的总大小超过3500个字符 .

  • 111

    我知道 accepted 答案 . 但是,如果答案因任何原因不适合他们,以下可能会对未来的读者有所帮助 .

    Angular不像jQuery那样执行ajax . 虽然我试图按照指南修改angular $httpprovider ,但我遇到了其他问题 . 例如 . 我使用codeigniter,其中 $this->input->is_ajax_request() 函数总是失败(由另一个程序员编写并全局使用,因此无法更改)说这不是真正的ajax请求 .

    为了解决这个问题,我接受了deferred promise的帮助 . 我在Firefox中测试了它,ie9并且它工作正常 .

    我有以下函数定义 outside 任何角度代码 . 这个函数定期进行jquery ajax调用并返回deferred / promise(我还在学习)对象 .

    function getjQueryAjax(url, obj){
        return $.ajax({
            type: 'post',
            url: url,
            cache: true,
            data: obj
        });
    }
    

    然后我使用以下代码将其称为角度代码 . 请注意,我们必须使用 $scope.$apply() 手动更新 $scope .

    var data = {
            media: "video",
            scope: "movies"
        };
        var rPromise = getjQueryAjax("myController/getMeTypes" , data);
        rPromise.success(function(response){
            console.log(response);
            $scope.$apply(function(){
                $scope.testData = JSON.parse(response);
                console.log($scope.testData);
            });
        }).error(function(){
            console.log("AJAX failed!");
        });
    

    这可能不是一个完美的答案,但它允许我使用带有角度的jquery ajax调用并允许我更新 $scope .

  • 5

    我在express中有同样的问题..要解决你必须使用bodyparser解析json对象才能发送http请求..

    app.use(bodyParser.json());
    
  • 339

    我使用asp.net WCF webservices与角度js和下面的代码工作:

    $http({
            contentType: "application/json; charset=utf-8",//required
            method: "POST",
            url: '../../operation/Service.svc/user_forget',
            dataType: "json",//optional
            data:{ "uid_or_phone": $scope.forgettel, "user_email": $scope.forgetemail },
            async: "isAsync"//optional
    
           }).success( function (response) {
    
             $scope.userforgeterror = response.d;                    
           })
    

    希望能帮助到你 .

  • 4

    没有找到如何使用$ http.post方法将数据发送到服务器的完整代码片段以及为什么它在这种情况下不起作用 .

    以下代码片段的说明......

    • 我正在使用jQuery $ .param函数将JSON数据序列化为www post数据

    • 在config变量中设置Content-Type,该变量将与angularJS $ http.post的请求一起传递,该请求指示服务器我们以www post格式发送数据 .

    • 注意$ htttp.post方法,我将第一个参数作为url发送,第二个参数作为数据(序列化)发送,第三个参数作为config发送 .

    剩下的代码是自我理解的 .

    $scope.SendData = function () {
               // use $.param jQuery function to serialize data from JSON 
                var data = $.param({
                    fName: $scope.firstName,
                    lName: $scope.lastName
                });
    
                var config = {
                    headers : {
                        'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
                    }
                }
    
                $http.post('/ServerRequest/PostDataResponse', data, config)
                .success(function (data, status, headers, config) {
                    $scope.PostDataResponse = data;
                })
                .error(function (data, status, header, config) {
                    $scope.ResponseDetails = "Data: " + data +
                        "<hr />status: " + status +
                        "<hr />headers: " + header +
                        "<hr />config: " + config;
                });
            };
    

    查看$http.post method here的代码示例 .

  • 5

    如果你使用PHP,这是一个从AngularJS POST访问PHP数组的简单方法 .

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

    如果使用 Angular >= 1.4 ,这是使用the serializer provided by Angular的最干净的解决方案:

    angular.module('yourModule')
      .config(function ($httpProvider, $httpParamSerializerJQLikeProvider){
        $httpProvider.defaults.transformRequest.unshift($httpParamSerializerJQLikeProvider.$get());
        $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
    });
    

    然后您可以在应用中的任何位置执行此操作:

    $http({
      method: 'POST',
      url: '/requesturl',
      data: {
        param1: 'value1',
        param2: 'value2'
      }
    });
    

    它将正确地将数据序列化为 param1=value1&param2=value2 并使用 application/x-www-form-urlencoded; charset=utf-8 Content-Type标头将其发送到 /requesturl ,因为它通常是 endpoints 上的POST请求所期望的 .

    TL;DR

    在我的研究过程中,我发现这个问题的答案有很多不同的风格;有些是非常复杂的,依赖于自定义函数,有些依赖于jQuery,有些不完整,建议你只需要设置 Headers .

    如果您只设置了 Content-Type 标头,则结束点将看到POST数据,但它不会采用标准格式,因为除非您提供字符串作为 data ,或者手动序列化您的数据对象,否则它将全部序列化为默认情况下为JSON,可能不正确在 endpoints 解释 .

    例如如果在上面的示例中未设置正确的序列化程序,则会在 endpoints 中看到:

    {"param1":"value1","param2":"value2"}
    

    这可能导致意外的解析,例如ASP.NET将其视为 null 参数名称,其中 {"param1":"value1","param2":"value2"} 为值;或者Fiddler以另一种方式解释它, {"param1":"value1","param2":"value2"} 作为参数名称, null 作为值 .

  • 4

    类似于OP _1328129的答案,除了使用 $http.post 而不仅仅是 $http 并仍然依赖于jQuery .

    在这里使用jQuery的好处是复杂的对象可以正常传递;反对手动转换为可能使数据混乱的URL参数 .

    $http.post( 'request-url', jQuery.param( { 'message': message } ), {
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
    });
    
  • 3

    当我遇到这个问题时,我发布的参数被证明是一个对象数组而不是一个简单的对象 .

  • 16

    刚刚从角度1.2更新到1.3,在代码中发现了一个问题 . 转换资源将导致无限循环,因为(我认为)$ promise再次保持相同的对象 . 也许它会帮助某人......

    我可以解决这个问题:

    [...]
      /**
     * 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;
    
    angular.forEach(obj, function(value, name) {
    +    if(name.indexOf("$promise") != -1) {
    +        return;
    +    }
    
        value = obj[name];
        if (value instanceof Array) {
            for (i = 0; i < value.length; ++i) {
    [...]
    
  • 3

    我已经使用了接受的答案代码(Felipe的代码)一段时间了,它一直很好用(谢谢,Felipe!) .

    但是,最近我发现它存在空对象或数组的问题 . 例如,提交此对象时:

    {
        A: 1,
        B: {
            a: [ ],
        },
        C: [ ],
        D: "2"
    }
    

    PHP似乎根本没有看到B和C.它得到了这个:

    [
        "A" => "1",
        "B" => "2"
    ]
    

    查看Chrome中的实际请求会显示以下内容:

    A: 1
    :
    D: 2
    

    我写了一个替代代码片段 . 它似乎与我的用例很好,但我没有广泛测试它,所以谨慎使用 .

    我使用TypeScript是因为我喜欢强类型,但很容易转换为纯JS:

    angular.module("MyModule").config([ "$httpProvider", function($httpProvider: ng.IHttpProvider) {
        // Use x-www-form-urlencoded Content-Type
        $httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8";
    
        function phpize(obj: Object | any[], depth: number = 1): string[] {
            var arr: string[] = [ ];
            angular.forEach(obj, (value: any, key: string) => {
                if (angular.isObject(value) || angular.isArray(value)) {
                    var arrInner: string[] = phpize(value, depth + 1);
                    var tmpKey: string;
                    var encodedKey = encodeURIComponent(key);
                    if (depth == 1) tmpKey = encodedKey;
                    else tmpKey = `[${encodedKey}]`;
                    if (arrInner.length == 0) {
                        arr.push(`${tmpKey}=`);
                    }
                    else {
                        arr = arr.concat(arrInner.map(inner => `${tmpKey}${inner}`));
                    }
                }
                else {
                    var encodedKey = encodeURIComponent(key);
                    var encodedValue;
                    if (angular.isUndefined(value) || value === null) encodedValue = "";
                    else encodedValue = encodeURIComponent(value);
    
                    if (depth == 1) {
                        arr.push(`${encodedKey}=${encodedValue}`);
                    }
                    else {
                        arr.push(`[${encodedKey}]=${encodedValue}`);
                    }
                }
            });
            return arr;
        }
    
        // Override $http service's default transformRequest
        (<any>$httpProvider.defaults).transformRequest = [ function(data: any) {
            if (!angular.isObject(data) || data.toString() == "[object File]") return data;
            return phpize(data).join("&");
        } ];
    } ]);
    

    它的效率低于Felipe的代码,但我认为这并不重要,因为与HTTP请求本身的总体开销相比,它应该是立竿见影的 .

    现在PHP显示:

    [
        "A" => "1",
        "B" => [
            "a" => ""
        ],
        "C" => "",
        "D" => "2"
    ]
    

    据我所知,不可能让PHP认识到B.a和C是空数组,但至少出现了键,这对于依赖于某个结构的代码很重要,即使它本身是空的 .

    另请注意,它将undefined和null转换为空字符串 .

  • 5

    我通过以下代码解决了这个问题

    客户端(Js):

    $http({
                    url: me.serverPath,
                    method: 'POST',
                    data: data,
                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                }).
                    success(function (serverData) {
                        console.log("ServerData:", serverData);
        ......
    

    注意数据是一个对象 .

    在服务器上(ASP.NET MVC):

    [AllowCrossSiteJson]
            public string Api()
            {
                var data = JsonConvert.DeserializeObject<AgentRequest>(Request.Form[0]);
                if (data == null) return "Null Request";
                var bl = Page.Bl = new Core(this);
    
                return data.methodName;
            }
    

    并且跨域请求需要'AllowCrossSiteJsonAttribute':

    public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
                base.OnActionExecuting(filterContext);
            }
        }
    

    希望这很有用 .

  • 2

    它's not angular'的错 . Angular旨在在JSON世界中工作 . 因此,当$ http服务发送AJAX请求时,它会将所有数据作为有效负载发送,而不是作为表单数据发送,以便后端应用程序可以处理它 . 但是jQuery在内部做了一些事情 . 您指示jQuery的$ ajax模块将表单数据绑定为JSON,但在发送AJAX请求之前,它序列化了JSON并添加了 application/x-www-form-urlencoded 标头 . 这样,您的后端应用程序能够以post参数的形式接收表单数据,而不是JSON .

    但您可以修改角度$ http服务的默认行为

    • 添加 Headers

    • 序列化json

    $ httpParamSerializerJQLike是angular的内置服务,它以与.JQuery的$ .param相同的方式序列化json .

    $http({
        method: 'POST',
        url: 'request-url',
        data: $httpParamSerializerJQLike(json-form-data),
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8;'
        }
    });
    

    如果你需要一个插件来首先将表单数据序列化为JSON,请使用这个https://github.com/marioizquierdo/jquery.serializeJSON

相关问题