AngularJS-$ http.post是否可以发送请求参数而不是JSON?


116

我有一些旧代码通过jQuery的post方法发出AJAX POST请求,看起来像这样:

$.post("/foo/bar", requestData,
    function(responseData)
    {
        //do stuff with response
    }

requestData 只是具有一些基本字符串属性的javascript对象。

我正在移动我们的内容以使用Angular,并且我想用$ http.post代替此调用。我提出以下内容:

$http.post("/foo/bar", requestData).success(
    function(responseData) {
        //do stuff with response
    }
});

当我这样做时,我从服务器收到500错误响应。使用Firebug,我发现这发送了如下请求体:

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

成功的jQuery $.post发送如下内容:

param1=value1&param2=value2&param3=value3

我要命中的端点期望请求参数而不是JSON。因此,我的问题是无论如何要告诉$http.post发送JavaScript对象作为请求参数而不是JSON?是的,我知道我可以自己从对象构造字符串,但是我想知道Angular是否为此提供了开箱即用的功能。

Answers:


140

我认为paramsconfig参数在这里不起作用,因为它会将字符串添加到url而不是正文中,但要添加到Infeligo建议的内容中,这是默认转换的全局替代示例(使用jQuery param作为转换示例数据到参数字符串)。

设置全局transformRequest函数:

var app = angular.module('myApp');

app.config(function ($httpProvider) {
    $httpProvider.defaults.transformRequest = function(data){
        if (data === undefined) {
            return data;
        }
        return $.param(data);
    }
});

这样,对$ http.post的所有调用都会自动将主体转换为jQuery $.post调用所使用的相同参数格式。

请注意,您可能还需要按以下方式在每次调用或全局设置Content-Type标头:

$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';

每个调用的样本非全局transformRequest:

    var transform = function(data){
        return $.param(data);
    }

    $http.post("/foo/bar", requestData, {
        headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
        transformRequest: transform
    }).success(function(responseData) {
        //do stuff with response
    });

我想知道是否还有其他东西,而不是拥有transformRequest函数,但是听起来好像没有。感谢您了解jQuery param函数。
dnc253

非全局每次调用方法对我来说效果很好,但是当尝试通过进行全局设置时$httpProvider.defaults,它不起作用,对此有任何线索吗?
Dfr

1
WRT全局配置它,我也遇到问题。当我尝试使用此处提供的代码段执行此操作时,出现错误Cannot read property "jquery" of undefined.如何解决此问题?PS。按呼叫转换有效。
kshep92

@ kshep92发生的事情是在没有数据的请求上调用了transformRequest函数,因此未定义“数据”。我在“返回$ .param(data);”之前添加了一个防护。将其作为第一行插入transformRequest函数:'if(data === undefined)返回数据;' 查看我对答案所做的编辑。
Jere.Jones,

1
从Angular 1.4开始,您可以使用$ httpParamSerializer代替jQuery docs.angularjs.org/api/ng/service/$httpParamSerializer
TheRemix 2015年

21

如果使用Angular> = 1.4,这是我发现的最干净的解决方案,它不依赖任何自定义或外部:

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/requesturl使用application/x-www-form-urlencoded; charset=utf-8Content-Type标头将其发送到端点,这通常是端点上的POST请求所期望的。


17

从AngularJS文档中:

params – {Object。} –字符串或对象的映射,它将在URL后变成?key1 = value1&key2 = value2。如果该值不是字符串,它将被JSON化。

因此,提供字符串作为参数。如果您不想这样做,请使用转换。再次,从文档中:

要在本地覆盖这些转换,请将转换函数指定为config对象的transformRequest和/或transformResponse属性。若要全局覆盖默认转换,请覆盖$ httpProvider的$ httpProvider.defaults.transformRequest和$ httpProvider.defaults.transformResponse属性。

有关更多详细信息,请参考文档


我在文档中看到了参数,就像Gloopy提到的那样,我需要它在正文中,而不是URL中。我想知道是否有某些选项或某些我缺少的参数来代替JSON,但听起来我只需要使用transformRequest属性。
dnc253

15

使用jQuery的$.param功能来序列化requestData中的JSON数据。

简而言之,使用与您类似的代码:

$http.post("/foo/bar",
$.param(requestData),
{
    headers:
    {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    }
}
).success(
    function(responseData) {
        //do stuff with response
    }
});

要使用此功能,您必须在页面中包含jQuery和AngularJS。


7

请注意,从Angular 1.4开始,您可以在不使用jQuery的情况下序列化表单数据。

在app.js中:

module.run(function($http, $httpParamSerializerJQLike) {
  $http.defaults.transformRequest.unshift($httpParamSerializerJQLike);
});

然后在您的控制器中:

$http({
    method: 'POST',
    url: myUrl',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: myData
});

这个答案很好。它解决了Angular中Post的两个主要问题。标头必须正确设置,并且您必须序列化json数据。如果不需要IE8支持,请使用1.4或更高版本。
mbokil '16

我刚刚实现了这一点,它解决了我在post上遇到的问题,但这也改变了patch的工作方式,并且似乎破坏了我对$ http.patch()的所有使用。
Mike Feltman

5

这可能有点hack,但我避免了这个问题,并将json转换为服务器端的PHP POST数组:

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

我使用过这种方法,但是我讨厌它。花了我很长时间才弄清楚为什么我必须使用它。
meconroy

就像我说的-感觉很hack。像大多数php一样;)
TimoSolo 2015年

5

由于$ resource缓存了请求,因此在设置自定义http身份验证时也遇到了问题。

为了使其正常工作,您必须这样做来覆盖现有的标头

var transformRequest = function(data, headersGetter){
  var headers = headersGetter();
  headers['Authorization'] = 'WSSE profile="UsernameToken"';
  headers['X-WSSE'] = 'UsernameToken ' + nonce
  headers['Content-Type'] = 'application/json';
};

return $resource(
  url,
    {
    },
    {
      query: {
        method: 'POST',
        url: apiURL + '/profile',
        transformRequest: transformRequest,
        params: {userId: '@userId'}
      },
    }
);

我希望我能帮助别人。我花了三天的时间才弄清楚这一点。


我想您为我节省了3天的工作时间。谢谢!!!我仍在尝试找出是否可以某种方式拦截请求调用,以便为每个调用注入自定义标头。
marcoseu 2013年

4

修改默认标题:

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

然后使用JQuery的$.param方法:

var payload = $.param({key: value});
$http.post(targetURL, payload);

3
   .controller('pieChartController', ['$scope', '$http', '$httpParamSerializerJQLike', function($scope, $http, $httpParamSerializerJQLike) {
        var data = {
                TimeStamp : "2016-04-25 12:50:00"
        };
        $http({
            method: 'POST',
            url: 'serverutilizationreport',
            headers: {'Content-Type': 'application/x-www-form-urlencoded'},
            data: $httpParamSerializerJQLike(data),
        }).success(function () {});
    }
  ]);

根据我的最简单,最容易的......可能有很多其他的方式
罗希特Luthra

2

快速调整-对于那些在transformRequest函数的全局配置方面遇到麻烦的人,以下是我用来消除Cannot read property 'jquery' of undefined错误的代码段:

$httpProvider.defaults.transformRequest = function(data) {
        return data != undefined ? $.param(data) : null;
    }


0

我发现这个问题有很多问题。我从express(无类型)和bodyParser(与dt〜body-parser类型)中使用它。

我没有尝试上传文件,而是简单地解释了发布字符串中给出的JSON。

request.body只是一个空的JSON({})。

经过大量调查,最终这对我有用:

import { json } from 'body-parser';
...
app.use(json()); <-- should be defined before the first POST handler!

application/json在客户端的请求字符串中提供内容类型也很重要。


对于“牺牲一只黑母鸡”式的答案,我感到抱歉,不幸的是,在当前的打字稿/节点/角度环境中,这种现象很普遍。
peterh-恢复莫妮卡

0

AngularJS v1.4.8 +(v1.5.0)的语法

       $http.post(url, data, config)
            .then(
                    function (response) {
                        // success callback
                    },
                    function (response) {
                        // failure callback
                    }
            );

例如:

    var url = "http://example.com";

    var data = {
        "param1": "value1",
        "param2": "value2",
        "param3": "value3"
    };

    var config = {
        headers: {
            'Content-Type': "application/json"
        }
    };

    $http.post(url, data, config)
            .then(
                    function (response) {
                        // success callback
                    },
                    function (response) {
                        // failure callback
                    }
            );
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.