如何将数据作为表单数据而不是请求有效负载发布?

mji*_*son 517 ajax post angularjs angular-http

在下面的代码中,AngularJS $http方法调用URL,并将xsrf对象作为"请求有效负载"提交(如Chrome调试器网络选项卡中所述).jQuery $.ajax方法执行相同的调用,但将xsrf提交为"Form Data".

如何让AngularJS将xsrf作为表单数据而不是请求有效负载提交?

var url = 'http://somewhere.com/';
var xsrf = {fkey: 'xsrf key'};

$http({
    method: 'POST',
    url: url,
    data: xsrf
}).success(function () {});

$.ajax({
    type: 'POST',
    url: url,
    data: xsrf,
    dataType: 'json',
    success: function() {}
});
Run Code Online (Sandbox Code Playgroud)

mji*_*son 608

需要将以下行添加到传递的$ http对象中:

headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
Run Code Online (Sandbox Code Playgroud)

并且传递的数据应转换为URL编码的字符串:

> $.param({fkey: "key"})
'fkey=key'
Run Code Online (Sandbox Code Playgroud)

所以你有类似的东西:

$http({
    method: 'POST',
    url: url,
    data: $.param({fkey: "key"}),
    headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
})
Run Code Online (Sandbox Code Playgroud)

来自:https://groups.google.com/forum/#!msg/angular/5nAedJ1LyO0/4Vj_72EZcDsJ

UPDATE

要使用AngularJS V1.4添加的新服务,请参阅

  • +1 @mjibson,对我来说,即使传递标题也没有用,直到我看到你的答案包含这个:`var xsrf = $ .param({fkey:"key"});`多数民众赞成愚蠢,为什么不能做角度呢它在内部? (51认同)
  • 不要使用jQuery的param函数,只需在$ http请求上设置params属性,只要Content-Type标题为'application/x-www-form-urlencoded',它就会执行jQuery.param方法的操作 - http ://stackoverflow.com/questions/18967307/jquery-ajax-request-works-same-angularjs-ajax-request-doesnt/18967966#18967966 (25认同)
  • @spig是的,它会执行jQuery.param所做的事情,但是,如果你使用params属性,你的属性将被编码为请求URL的一部分而不是在正文中 - 即使你已经指定了application/x-www- form-urlencoded标头. (13认同)
  • 为了更接近$ .ajax默认行为,还应在内容类型标题中指定charset - `headers:{Content-Type':'application/x-www-form-urlencoded; 字符集= UTF-8' }` (12认同)
  • 有没有办法让数据的json> url编码自动发生,或者为每个POST或PUT方法指定这种情况? (3认同)
  • 截至 2016 年,可以按照此处所述进行操作:https://docs.angularjs.org/api/ng/service/$httpParamSerializerJQLike (2认同)

Ant*_*ony 193

如果你不想在解决方案中使用jQuery,你可以试试这个.从这里获得解决方案/sf/answers/120042961/

$http({
    method: 'POST',
    url: url,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    transformRequest: function(obj) {
        var str = [];
        for(var p in obj)
        str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
        return str.join("&");
    },
    data: xsrf
}).success(function () {});
Run Code Online (Sandbox Code Playgroud)

  • 请注意,与$ .param()相比,此方法不能在数组/对象上递归工作. (10认同)
  • 这个方法适用于角度1.2.x,我认为这是最好的答案,因为它很优雅,它在核心角度工作,不依赖于任何外部库,如jQuery. (7认同)
  • 在$ resource操作中使用此方法时遇到了问题.表单数据还包括$ get,$ save等函数.解决方案是改变`for`语句,使用`angular.forEach`代替. (2认同)

Eze*_*tor 91

围绕这个问题的持续困惑激发了我写一篇关于它的博客文章.我在这篇文章中提出的解决方案优于您当前的最高评级解决方案,因为它不会限制您为$ http服务调用参数化数据对象; 即使用我的解决方案,您可以继续将实际数据对象传递给$ http.post()等,并仍然可以实现所需的结果.

此外,最受欢迎的答案依赖于在$ .param()函数的页面中包含完整的jQuery,而我的解决方案是jQuery不可知,纯粹的AngularJS就绪.

http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/

希望这可以帮助.

  • +1详细博客,但事实上需要这个是可怕的...... (10认同)
  • 是的,在两个层面上可能很糟糕:1)AngularJS决定颠覆_de facto_(虽然不可否认的误导)标准,2)PHP(以及谁知道其他任何服务器端语言)以某种方式不会自动检测application/json输入.:P (4认同)
  • 我(和许多其他人一样)遇到这个问题,我的后端`ASP.NET`并没有'本地'支持这一点.如果你不想改变AngularJS的行为(我没有,因为我的API返回JSON,为什么不接受JSON,它比表单数据更灵活)你可以从[`Request.InputStream`中读取](http://msdn.microsoft.com/en-us/library/system.web.httprequest.inputstream.aspx)然后以任何你想要的方式处理它.(为了便于使用,我选择将其反序列化为[`dynamic`](http://msdn.microsoft.com/en-us/library/vstudio/dd264741.aspx).) (4认同)
  • 拒绝投票,是因为[这不是一个独立的答案](http://meta.stackexchange.com/a/8259/150070)。好的答案不只是链接到其他地方。摘自[如何回答](http://stackoverflow.com/help/how-to-answer):“万一引用重要链接中最相关的部分,以防目标站点无法访问或永久脱机。” (2认同)

kza*_*zar 82

我拿了一些其他的答案并做了一些更清洁的东西,把这个.config()调用放在app.js中angular.module的末尾:

.config(['$httpProvider', function ($httpProvider) {
  // Intercept POST requests, convert to standard form encoding
  $httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
  $httpProvider.defaults.transformRequest.unshift(function (data, headersGetter) {
    var key, result = [];

    if (typeof data === "string")
      return data;

    for (key in data) {
      if (data.hasOwnProperty(key))
        result.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key]));
    }
    return result.join("&");
  });
}]);
Run Code Online (Sandbox Code Playgroud)

  • 还要注意使用`unshift()`,以便其他转换保持不受干扰.干得好. (3认同)
  • 你是老板.这是一个很好的代码snippit. (2认同)
  • 完善!对我来说工作得很好!悲伤的角度本身并不支持这一点. (2认同)
  • 这个答案应该是正确的答案,其他人是错的,谢谢你的队友! (2认同)
  • 递归编码怎么样? (2认同)

Mit*_*tja 57

从AngularJS v1.4.0开始,有一个内置$httpParamSerializer服务,可以根据文档页面上列出的规则将任何对象转换为HTTP请求的一部分.

它可以像这样使用:

$http.post('http://example.com', $httpParamSerializer(formDataObj)).
    success(function(data){/* response status 200-299 */}).
    error(function(data){/* response status 400-999 */});
Run Code Online (Sandbox Code Playgroud)

请记住,对于正确的表单帖子,Content-Type必须更改标题.要为所有POST请求全局执行此操作,可以使用此代码(取自Albireo的半答案):

$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
Run Code Online (Sandbox Code Playgroud)

要仅对当前帖子执行此操作,headers需要修改request-object 的属性:

var req = {
 method: 'POST',
 url: 'http://example.com',
 headers: {
   'Content-Type': 'application/x-www-form-urlencoded'
 },
 data: $httpParamSerializer(formDataObj)
};

$http(req);
Run Code Online (Sandbox Code Playgroud)


Alb*_*reo 24

您可以全局定义行为:

$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
Run Code Online (Sandbox Code Playgroud)

所以你不必每次都重新定义它:

$http.post("/handle/post", {
    foo: "FOO",
    bar: "BAR"
}).success(function (data, status, headers, config) {
    // TODO
}).error(function (data, status, headers, config) {
    // TODO
});
Run Code Online (Sandbox Code Playgroud)

  • 你的例子是错的......你正在修改的只是标题.数据本身仍将是JSON编码的,并且无法读取JSON的旧服务器无法读取. (45认同)

Jam*_*ell 20

作为一种解决方法,您可以简单地使接收POST的代码响应application/json数据.对于PHP,我添加了下面的代码,允许我以form-encoded或JSON对它进行POST.

//handles JSON posted arguments and stuffs them into $_POST
//angular's $http makes JSON posts (not normal "form encoded")
$content_type_args = explode(';', $_SERVER['CONTENT_TYPE']); //parse content_type string
if ($content_type_args[0] == 'application/json')
  $_POST = json_decode(file_get_contents('php://input'),true);

//now continue to reference $_POST vars as usual
Run Code Online (Sandbox Code Playgroud)


Ser*_*gan 16

这些答案看起来像疯狂的矫枉过正,有时,简单就是更好:

$http.post(loginUrl, "userName=" + encodeURIComponent(email) +
                     "&password=" + encodeURIComponent(password) +
                     "&grant_type=password"
).success(function (data) {
//...
Run Code Online (Sandbox Code Playgroud)


小智 9

您可以尝试以下解决方案

$http({
        method: 'POST',
        url: url-post,
        data: data-post-object-json,
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        transformRequest: function(obj) {
            var str = [];
            for (var key in obj) {
                if (obj[key] instanceof Array) {
                    for(var idx in obj[key]){
                        var subObj = obj[key][idx];
                        for(var subKey in subObj){
                            str.push(encodeURIComponent(key) + "[" + idx + "][" + encodeURIComponent(subKey) + "]=" + encodeURIComponent(subObj[subKey]));
                        }
                    }
                }
                else {
                    str.push(encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]));
                }
            }
            return str.join("&");
        }
    }).success(function(response) {
          /* Do something */
        });
Run Code Online (Sandbox Code Playgroud)


Ozg*_*gur 8

为帖子创建适配器服务:

services.service('Http', function ($http) {

    var self = this

    this.post = function (url, data) {
        return $http({
            method: 'POST',
            url: url,
            data: $.param(data),
            headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        })
    }

}) 
Run Code Online (Sandbox Code Playgroud)

在控制器或其他任何地方使用它:

ctrls.controller('PersonCtrl', function (Http /* our service */) {
    var self = this
    self.user = {name: "Ozgur", eMail: null}

    self.register = function () {
        Http.post('/user/register', self.user).then(function (r) {
            //response
            console.log(r)
        })
    }

})
Run Code Online (Sandbox Code Playgroud)


rob*_*tra 7

有一个非常好的教程可以解释这个和其他相关的东西 - 提交AJAX表单:AngularJS方式.

基本上,您需要设置POST请求的标头以指示您将表单数据作为URL编码的字符串发送,并将要发送的数据设置为相同的格式

$http({
  method  : 'POST',
  url     : 'url',
  data    : $.param(xsrf),  // pass in data as strings
  headers : { 'Content-Type': 'application/x-www-form-urlencoded' }  // set the headers so angular passing info as form data (not request payload)
});
Run Code Online (Sandbox Code Playgroud)

请注意,此处使用jQuery的param()辅助函数将数据序列化为字符串,但如果不使用jQuery,也可以手动执行此操作.


小智 7

var fd = new FormData();
    fd.append('file', file);
    $http.post(uploadUrl, fd, {
        transformRequest: angular.identity,
        headers: {'Content-Type': undefined}
    })
    .success(function(){
    })
    .error(function(){
    });
Run Code Online (Sandbox Code Playgroud)

请结账! https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs