ChatGPT解决这个技术问题 Extra ChatGPT

AngularJS - Any way for $http.post to send request parameters instead of JSON?

I have some old code that is making an AJAX POST request through jQuery's post method and looks something like this:

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

requestData is just a javascript object with some basic string properties.

I'm in the process of moving our stuff over to use Angular, and I want to replace this call with $http.post. I came up with the following:

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

When I did this, I got a 500 error response from the server. Using Firebug, I found that this sent the request body like this:

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

The successful jQuery $.post sends the body like this:

param1=value1&param2=value2&param3=value3

The endpoint I am hitting is expecting request parameters and not JSON. So, my question is is there anyway to tell $http.post to send up the javascript object as request parameters instead of JSON? Yes, I know I could construct the string myself from the object, but I want to know if Angular provides anything for this out of the box.


o
ocodo

I think the params config parameter won't work here since it adds the string to the url instead of the body but to add to what Infeligo suggested here is an example of the global override of a default transform (using jQuery param as an example to convert the data to param string).

Set up global transformRequest function:

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

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

That way all calls to $http.post will automatically transform the body to the same param format used by the jQuery $.post call.

Note you may also want to set the Content-Type header per call or globally like this:

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

Sample non-global transformRequest per call:

    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
    });

I was wondering if there was something other than having a transformRequest function, but it sounds like there's not. Thanks for heads up about the jQuery param function.
Non-global per call method is working well for me, but when trying to set up globally via $httpProvider.defaults, then it not working, any clue about this ?
WRT configuring it globally, I too am having issues. When I try to do it using the snippet given here, I get an error Cannot read property "jquery" of undefined. How do I fix this? PS. Per-call transformations work.
@kshep92 What is happening is that the transformRequest function is getting called on a request with no data so 'data' is undefined. I added a guard prior to 'return $.param(data);'. Insert this as the first line to the transformRequest function: 'if (data === undefined) return data;' See the edit I made to the answer.
as of Angular 1.4 you can use $httpParamSerializer instead of jQuery docs.angularjs.org/api/ng/service/$httpParamSerializer
S
Saeb Amini

If using Angular >= 1.4, here's the cleanest solution I've found that doesn't rely on anything custom or external:

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';
});

And then you can do this anywhere in your app:

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

And it will correctly serialize the data as param1=value1&param2=value2 and send it to /requesturl with the application/x-www-form-urlencoded; charset=utf-8 Content-Type header as it's normally expected with POST requests on endpoints.


I
Infeligo

From AngularJS documentation:

params – {Object.} – Map of strings or objects which will be turned to ?key1=value1&key2=value2 after the url. If the value is not a string, it will be JSONified.

So, provide string as parameters. If you don't want that, then use transformations. Again, from the documentation:

To override these transformation locally, specify transform functions as transformRequest and/or transformResponse properties of the config object. To globally override the default transforms, override the $httpProvider.defaults.transformRequest and $httpProvider.defaults.transformResponse properties of the $httpProvider.

Refer to documentation for more details.


I saw the params in the documentation, and like Gloopy mentions, I need it in the body, and not on the URL. I was wondering if there was some option or something I was missing to do the parameters instead of JSON, but it sounds like I just need to use the transformRequest property.
S
Sagar Bhosale

Use jQuery's $.param function to serialize the JSON data in requestData.

In short, using similar code as yours:

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

For using this, you have to include jQuery in your page along with AngularJS.


R
Ram

Note that as of Angular 1.4, you can serialize the form data without using jQuery.

In the app.js:

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

Then in your controller:

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

This answer is great. It addresses the 2 main problems with Post from Angular. The header must be set correctly and you have to serialize the json data. If you don't need IE8 support use 1.4+ or later.
I just implemented this and it resolves issues I was having with post, but this also changes how patch works and appears to have broken all of my uses of $http.patch().
T
TimoSolo

This might be a bit of a hack, but I avoided the issue and converted the json into PHP's POST array on the server side:

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

I've used this method, but I hate it; and took me a long time to figure out why I had to use this.
like I said - it feels hacky. Like most of php ;)
s
sudo bangbang

I have problems as well with setting custom http authentication because $resource cache the request.

To make it work you have to overwrite the existing headers by doing this

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'}
      },
    }
);

I hope I was able to help someone. It took me 3 days to figure this one out.


I guess you just saved me 3 days of work. Thanks!!! I am still trying to figure out if I can intercept request call somehow so that I can inject a custom header for every call.
Z
Zags

Modify the default headers:

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

Then use JQuery's $.param method:

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

R
Rohit Luthra
   .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 () {});
    }
  ]);

According to me its simplest and easiest...There may be many other ways
k
kshep92

Quick adjustment - for those of you having trouble with the global configuration of the transformRequest function, here's the snippet i'm using to get rid of the Cannot read property 'jquery' of undefined error:

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

v
vikramaditya234

You can also solve this problem without changing code in server, changing header in $http.post call and use $_POST the regular way. Explained here: http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/


p
peterh

I found many times problematic behavior of this whole. I used it from express (without typings) and the bodyParser (with the dt~body-parser typings).

I didn't try to upload a file, instead simply to interpret a JSON given in a post string.

The request.body was simply an empty json ({}).

After a lot of investigation finally this worked for me:

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

It may be also important to give the application/json content type in the request string from the client side.


I am sorry for the "and sacrifice a black hen"-style answer, what is unfortunately common in the current stage of the typescript/node/angular environment.
p
pvrforpranavvr

Syntax for AngularJS v1.4.8 + (v1.5.0)

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

Eg:

    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
                    }
            );