I was tried to use AngularJS $http and coffeescript to send a cross domain post request. I've already changed the server side to make it available for cross domain request.
The question is when I was using Angular js to send request I found the request data is different from the request sent by jQuery.
login: (user, callback)=>
baseUrl = 'http://localhost:3000/api/v1/sessions'
@$http({
method: 'POST',
url: baseUrl,
data: {
"user":{
"email":"[email protected]",
"password":"123456"
}
},
headers:
'Content-Type': 'application/x-www-form-urlencoded'
}).success (result)->
callback(result)
then I got
$.ajax({
type: "POST",
url: "http://localhost:3000/api/v1/sessions",
data: {
"user":{
"email":"[email protected]",
"password":"123456"
}
},
success: function(){
}
Then it works well, this request data format is what I want.
I don't know whether it's an issue, hope someone can help me out.
There is same question I posted on stackoverflow: http://stackoverflow.com/questions/21400743/angularjs-cant-send-post-request-with-content-typeapplication-json
You're asking for x-www-form-urlencoded, and angular doesn't encode data that way currently. I suppose we could, but I'm not sure I expect that to happen. I think for the time being you should just use jQuery when you need to send requests like this, and maybe if you want to implement this feature we could look at getting it into the tree. I'll mark this as PRz welcome.
Related to https://github.com/angular/angular.js/issues/1743. I agree with @caitp that we could easily make people's life a bit easier. I guess we could try to do is:
x-www-form-urlencoded
header and serialise data accordinglyWould it make sense for this functionality to live in a stand-alone module outside of core? Having it outside of core would make it easy to extend it and support other formats in the same way.
I put together a proof of concept, and a Plunker demo. If this seems like the right direction, I'd be happy to continue development on it.
+1
From personal observation, all I need to do to get this working is to wrap the data
property around with jQuery's $.param
to get form posting working as it does normally.
Ex.
$http({
url: ServerAddress+"/login", method: 'POST',
data: $.param($scope.loginForm),
headers : {'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'}
})
I feel it would just make life easier if AngularJS could provide an equivalent function to jQuery's $.param
- ideally something that can be used also with the transformRequest
property.
+1. Coming here from the thread at #1743, I agree that this is a feature that is missing from Angular. My team was actually quite surprised to find that there were hoops to jump through to make a regular form post. In our case we have jQuery as a dependency, so we can use that until Angular has a "native" solution.
Facing the same issue as well. Recently started working on a HTML5 app (Cordova) which calls a PHP backend for HTTP requests. The PHP backend is powering a number of different projects so even simple calls like login and authentication expect form-data
or application/x-www-form-urlencoded
.
I've really liked the bits of AngularJS I've used but this came off as a very odd omission. Even if url-encoding isn't the standard when posting data, it is the convention expected by an overwhelming number of backend services, and Angular should support it out of the box.
expected by an overwhelming number of backend services
lets enumerate those services, particularly the ones where this is the only possible solution and it's simply impossible to do anything else
after we've done that and established how big of a problem this is, because most people don't seem to run into this issue.
lets enumerate those services, particularly the ones where this is the only possible solution and it's simply impossible to do anything else
There's almost always a workaround to things. I don't think you'll get a service where it's literally impossible to send forms with the current Angular implementation.
As I mentioned in my post, in the end, I only needed jQuery's $.param
to change my data into something my service (golang backend) could digest.
However, it did take me an extremely long time before I managed to realise the reason why my forms weren't sending and to find this workaround I'm currently using. It would be great if Angular could provide an internal function similar to $.param
, or at the very least mention this problem and possible solutions in the API reference page / wiki.
A workaround for everything indeed, I never opened an issue because I assumed $.param was the defacto solution.
A native implementation would be great.
I have the exact same problem, php server does not accept OPTION method natively so I guess the problem is quite big.
I have used $http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded"; to switch requests to application/x-www-form-urlencoded to get the request through.
Unfortunately I do not have jQuery as a dependancy so $.param is not an option for me...are there any other workarounds?
There must already be a function for this in angular, as it does it for 'params' key passed to $http... but it is not publicly accessible. I think this should change and be made public, and the default transformRequest should be changed too to serialize forms according the content-type header.
For now though, if you do not want to reimplement the wheel over and over (even if its just 5 lines, I do agree it is bad news having to write it yourself), a clever trick I saw recently was to pass FormData object as data, no-op transformRequest so it doesn't get stringified as [object FormData] (offtopic, html5 spec wtf, why no adequate toString?), and undefined as content-type header so XHR.send will set correct multipart headers. For older browsers, there are FormData polyfills. Note the request becomes multipart instead of urlencoded though, often that is ok but for some backends it may still not cut it.
+1 I too am facing the same issue. Hope this can be resolved from Angular itself?
+1
Same here.. I don't want to add jQuery as a dependency just for this
Unbelievable, AngularJS is so awesome that I cannot believe this so simple thing is missing. So everyone is using jQuery only for this serialization function?
+1 It's pretty crazy such an advanced framework doesn't have this by default
+1 jQuery should not be required to fix this, pretty basic functionality, form submission...
This should really be prioritized for addition into the next version
yes, lot of apis expect 'jquery' way so this functionality is required
+1 for angular to incorporate this
+1
Another user here waiting for this...
I should not need to include jquery just for this... This issue should be a priority!
For those trying to find a better solution:
http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/
(This works, and I don't need to use jquery!)
:+1:
Thanks @rodrigograca31.
This sucks. Come on guys, people are spending hours on this.
I bet most just go and add JQuery which is ridiculous, and in my case impossible...
Just a heads up, this solution works great if you only need this to talk to Spring Security or something with simple requests
http://stackoverflow.com/a/14868725/564449
+1 So... what are you people doing to workaround this ?
+1 maybe it's not the standard but x-www-form-urlencoded is the most commonly used data format for AJAX post. I think at least AngularJS should give an option for that.
This solution works for me
http://bit.ly/1HE96tC
But i hope Angular can solve this soon.
This solution works for me
http://bit.ly/1HE96tC
The problem is that the most common _workaround_ for this being suggested is to use $.param
, which means having jQuery as a dependency. I'd rather not have jQuery included in my project only to serialize data for angular.
@UzEE exactly, and furthermore, everywhere you look for an answer, they are all the same: use jQuery
Thats something I really cant understand...
I think I will re-write a stand alone version of $.params... but would be much nicer if I dont have to :)
@UzEE and @Avcajaraville no need to re-write it... My solution (link above) works without jquery...
I just learn about angular, and this is a must have feature!
This is now (since 1.4) pretty trivial with the $httpParamSerializerJQLike
:
.controller('myCtrl', function($http, $httpParamSerializerJQLike) {
$http({
method: 'POST',
url: baseUrl,
data: $httpParamSerializerJQLike({
"user":{
"email":"[email protected]",
"password":"123456"
}
}),
headers:
'Content-Type': 'application/x-www-form-urlencoded'
})
})
You can also move this logic into a transformRequest that does the transformation based on the header. Imo, this is now the right balance between easy and flexible.
$httpParamSerializerJQLike
can also be set for each $http
using config.paramSerializer
or set as default as $httpProvider.defaults.paramSerializer = $httpParamSerializerJQLike
With the above information, I think this can be closed.
@lgalfaso it is not about param serializing but body's data serializing. I believe there is a little bit of work here. I will take care of this.
How do i achieve this with $resource on 1.3
Just arrived at this discussion, but I don't think it's sufficient to provide $httpParamSerializerJQLike. What is needed here is for the POST machinery to understand that if I say the content is 'application/x-www-form-urlencoded' for it to apply the transform to the data automatically.
I've been trying to use $httpParamSerializerJQLike
as a solution to the problem like so:
angular.module('myApp', [])
.factory('myFactory', ['$http', $httpParamSerializerJQLike,
function($http , $httpParamSerializerJQLike ) {
var location = 'https://somelocation.com';
return {
check: function(user) {
return $http({
method: 'POST',
url: location,
data: $httpParamSerializerJQLike(user),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});
}
};
}
]);
And I get this error $httpParamSerializerJQLike is not defined
, maybe there something I'm missing.
Using Angular 1.4.4
@gillchristian: You need quotes round the first $httpParamSerializerJQLike so:
.factory('myFactory', ['$http', '$httpParamSerializerJQLike',
@AdamMcCormick thatnks! I missed that :grin:
Following code works like charm for older version
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
$httpProvider.defaults.transformRequest.unshift(function(data, headersGetter) {
var key, result = [],
response;
if (typeof data == 'string') {
response = data;
} else {
for (key in data) {
if (data.hasOwnProperty(key)) {
result.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
}
}
response = result.join('&');
}
return response;
});
@awebdeveloper "works like a charm" for the simple cases, yes.
its a far cry from the jquery serializer which works for nested structures as well.
and it falls under the 'reinventing the wheel' category i have gripes with.
@georgir The paramSerializer is available since 1.4. Have you noticed any bugs with it?
@Narretz My previous response was directed specifically at @awebdeveloper and his code regarding older versions, sorry I didn't make it clear and may have left the impression I am criticizing angular's current version or something.
But to answer you anyway, I haven't used 1.4 but from looking at the code it seems ok. Basically exactly what I wanted in my first post on the issue - expose the functionality used by $http "params" config option to be more generally accessible. Now users can call it for their data.
Additional features like the default request transformer using that serializer for the request data based on the content-type header as proposed by others in this thread probably still fall under this issue.
[And regarding the paramSerializers specifically - a missing "JQLike" feature of the "JQLike" serializer is the ability to handle array of {name, value} objects, to support same key appearing multiple times in the data, i.e. for cases like a[]=1&a[]=2&a[]=3
. Not a critical feature though, and not sure if this issue is the place to discuss that.]
/cc @Narretz
I am using AngularJS 1.4.6.
I have the following code in my module's config section but it does not work:
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
$httpProvider.defaults.paramSerializer = '$httpParamSerializerJQLike';
@armanforghani I can't test right now, but this should work. Can you set up a plnkr that shows the problem?
@Narretz Please see here
@armanforghani, the paramSerializers are for serializing URL query params, not the payload/data of the request.
In your plnkr, there are no params to serialize.
How can i serialize data for post request? Currently i use this way. Can you recommend better option?
I can' really recommend a better option, because I never need to serialize the payload ala jQuery.
If I had to, I would try https://github.com/angular/angular.js/issues/6039#issuecomment-113502695 as my first option though.
@armanforghani There's also an example in the docs: https://docs.angularjs.org/api/ng/service/$httpParamSerializerJQLike Let me know if that doesn'T work
It should be possible to have this behavior by default for all _post_ requests, you would need to do
// Warning, untested code
module.run(function($http, $httpParamSerializerJQLike) {
$http.defaults.transformRequest.unshift($httpParamSerializerJQLike);
});
@Narretz I'm looking for a way to set as default for all requests in module's config.
@lgalfaso Thank you. Interesting, i will try that.
@armanforghani please share if this actually worked, so other people can use the same mechanism if this is the behavior they are looking for
I just tested it and it works perfectly. @lgalfaso Thank you so much.
Given that there is a mechanism to achieve the desired behavior, then it should be safe to close this issue. If there is a spacial interest to make http request body data serialization configurable in an easier way, then open an issue linking this discussion.
@lgalfaso I really disagree that this solves the problem. There is only a small subset of POST requests for which this is the right serializer so adding it for all requests isn't a good solution for the general case. The framework should be changed to use this serializer any time 'application/x-www-form-urlencoded' is the data type. Otherwise the framework is submitting bad data
@AdamMcCormick I think it is perfectly fine to keep on with the discussion on data serialization for _POST_ requests. This includes what should be configurable, and if this configuration should be part of the core or a third-party module.
Now, there is no spec on how JSON data should be serialized. http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 This implies that there is no right or wrong way to serialize it. What you think is the _right_ way will be someone else wrong way.
The way data is serialized is configurable as shown before, how this is done is documented https://docs.angularjs.org/api/ng/service/$http#transforming-requests-and-responses and there are some tools for different serialization mechanisms.
The current mechanism make it possible to create a transformation that works different when the data time is 'application/x-www-form-urlencoded' or something else, as you have access to the request header.
Changing the default behavior would be a breaking change and something that we try to avoid. This is why there are several configuration points that, hopefully, will help developers make things work the way they need with minimal code.
With all this information, it is not clear to me what should be changed. Can you please provide an example of something that is not possible, or that would need a substantial number of LOC to achieve?
@pkozlowski-opensource you had a plan for this, right? Maybe you can outline what you would have done, and me or someone else can take a shot at it?
@Narretz @lgalfaso what I was thinking of is to change the defaults so if someone sets 'application/x-www-form-urlencoded'
as a header we would serialize differently (not using JSON but sth that "most people expect"). Obviously this would be a breaking change so can be only done in 1.5.x or 1.6.x
@lgalfaso when I say I want "application/x-www-form-urlencoded" data (by telling angular the content type) it shouldn't be sending JSON at all! It should be sending the data object I provide as if it's a WWW Form (as the spec clearly outlines), like I tell it to. I'm not sure why that's so hard to understand. The current behavior is not spec compliant and thus wrong, so breaking change or not, it should change. It's not about what I think, and it doesn't matter if there's a workaround. @pkozlowski-opensource has stated several times how a solution could be implemented, and I am saying it should be.
@AdamMcCormick, would it be possible to know what standard are you talking about?
https://xhr.spec.whatwg.org/#the-send()-method is the standard for _xhr_ that is what $http
abstracts. Here, how the body should be serialized is only specified for two cases; an HTML document or a string.
@lgalfaso you linked the spec for "application/x-www-form-urlencoded" above and it's pretty explicit as to how key/value pairs should be serialized and sent. When the content type is "application/x-www-form-urlencoded" the whole point is to emulate the way an HTML form would look if you had POST'd it. It's not a "body" it's a URL-encoded WWW form, it needs to act like it.
@AdamMcCormick the spec at http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 only applies to <form>
and it would be reasonable to think that this should also apply to FormData
objects, but there is nothing there that applies to JSON objects. At least none that I was able to find. If there is a spec that specifies this, please post it here as it would be a compelling reason to justify a breaking change. If not, then it is best to have a configurable option for the serializer, but keeping the current serializer as the default.
@lgalfaso It's NOT A JSON OBJECT. It's a JavaScript object that I am trying to use to replace a FORM. "application/x-www-form-urlencoded" is the data format, not "application/json." You are conflating the two and that's why you don't seem to be hearing me. http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 specifies what ANY data transmitted with a content type of "application/x-www-form-urlencoded" MUST adhere to. That's "a compelling reason to justify a breaking change." What's more compelling than the current mode of operation being explicitly wrong?
TL, DR:
The docs should state the behavior for $http
when serializing binary data, what is the default serialization and what serializations are available, if any beyond the default.
The best behavior in my opinion is that angular methods which result in a HTTP request should use a _configuration_ OR the _content-type_ header to decide which algorithm they will use for a serialization of binary data. In addition, if following the configuration route, Angular should set the correct content-type for the serialization chosen.
Now, there is no spec on how JSON data should be serialized.
JSON is the serialization, no need to serialize it again. :grin:
It is specified in a RFC@IETF and at json.org.
application/x-www-form-urlencoded is another serialization specified as part of the HTML specs.
The parameter data
from the $http
function is expected receive any of two data types:
String
: data in text format, it can be a text string or another data type serialized if needed
Object
: a binary object which will be serialized either by Angular or the User Agent before sent via HTTP. We already know Angular does serialize it as JSON by default and ignores the content-type header, if set.
Why does this look like a bug?
$http.[post|get|put|...] documentation does not state the default serialization method used by Angular when the "data" parameter is a javascript object and does not behave like the most popular javascript frameworks (jQuery, Mootools, ...). Nor it behaves like what is the default expected by the most popular server-side technologies (PHP, Java, ASP.net, ...)
To add, the documentation also do not state that $http will ignore "Content-type" and any other parameter header to decide which serialization method it will use.
This is one use-case leading people to this github issue
By using a PHP server and Angular without jQuery (which is useless for a Angular app) for the first time (like myself), you will almost invariably try:
$http.post(url, jsObject).then(...)
This will fail, PHP by default deserializes x-www-form-urlencoded
data into the $_POST
variable, not json
data.
Reviewing the Network inspector in firebug or chrome or dragonfly you may notice that the data has been serialized to JSON. No big deal:
Review your code, read the Angular docs. Find nothing wrong.
Expecting angular to serialize the binary data automatically into the most common serialization in HTTP, you will remember several other cases where you needed to explicitly set the data type as x-www-form-urlencoded
, try to set the http header and hope the framework honors it:
$http.post(url, jsObject, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}}).then(...)
When this fails, you will think you or the framework did something wrong and will read the docs again, ask around, search the web, ...
Somewhere near this point, you will learn about $httpParamSerializer
and maybe use it, go to the @angular issues page or both.
@ribeirobreno I agree completely. This has been my issue when working with angular 1 and after going throught exactly these steps and having to use $.param because I did not find out about $httpParamSerializer . After all this I came to the same problem with Angular 2 and now, again, my day is flying by while I'm trying to figure out how to do this without using jquery again since I have not been able to find $httpParamSerializer . What I'm interested even more is what backend framework are angular guys using not to come to this problem immediately since I've encountered this with both Flask and ASP.Net and on both the guys doing backend said it was my problem
@DominikDitoIvosevic i've looked into the docs today and found this: https://docs.angularjs.org/api/ng/service/$http#default-transformations
Don't know if i missed it before or if it was added... either way i think it would be really nice to have a reference to the "default transformations" next to the data parameters, here: https://docs.angularjs.org/api/ng/service/$http#usage
I realize I'm coming at this very (very) late, but as someone new to Angular, I'm amazed that it's so awkward to get a www-form-urlencoded
post body. I was very surprised that it _wasn't_ the default, given (as @ribeirobreno said, masterfully) it's what's used _everywhere else_. I still don't understand why this difference is not called out explicitly in the documentation. Like so many others in this thread, I'm using PHP as a backend. It's easier for me to make the transformation server-side than via Angular, partly because even with the transforms in Angular, getting "normal" post bodies and content headers is still too much work in Angular. Whether I make the adjustment in Angular or in PHP, it's still one more thing I have to explain to my novice students.
This is one of several closed issues I've found on this topic. I won't comment on all of them, but I hope that enough voices will bring some visibility to the issue and make this quirk of Angular easier to use.
As a newbie to Angular ! It helped me in 2017 :)
i faced to this problem in angular2
so i used this code here
http://stackoverflow.com/questions/35212341/angular2-http-post-request-parameters
Most helpful comment
From personal observation, all I need to do to get this working is to wrap the
data
property around with jQuery's$.param
to get form posting working as it does normally.Ex.
I feel it would just make life easier if AngularJS could provide an equivalent function to jQuery's
$.param
- ideally something that can be used also with thetransformRequest
property.