AngularsJS POST JSON data to Symfony2 - ajax

I would like to know why this is not working , I have a AngularJS app witch sends trough AJAX data to a Symfony2 Application. As you can see, data is sent in my network console
<?php
namespace Supbox\CloudBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
class FolderController extends Controller
{
public function createAction(){
$post = $this->getRequest()->request;
$name = $post->get("name");
$folder = $post->get("folder");
var_dump($post);
die;
}
}
AngularJS code
$http({
method: 'POST',
url: route.folder.create,
data: {
folder: $scope.id,
name: name
}
})
Opera Network Console Output
Request URL:http://localhost/supbox/web/box/folder/create
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept-Encoding:gzip,deflate,lzma,sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Content-Length:25
Content-Type:application/json;charset=UTF-8
Host:localhost
Origin:http://localhost
Referer:http://localhost/supbox/web/box/
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36 OPR/20.0.1387.82
Request Payloadview source
{folder:1, name:Ang}
Response Headersview source
Connection:Keep-Alive
Content-Length:431
Content-Type:text/html
Date:Mon, 24 Mar 2014 13:25:53 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.4.4 (Win64) OpenSSL/1.0.1d PHP/5.4.12
X-Powered-By:PHP/5.4.12

If you (Angular JS) post data through header as JSON you need to change your code like this:
public function createAction(){
$post = $this->getRequest()->getContent();
$post = json_decode($post);
$name = $post->name;
$folder = $post->folder;
var_dump($post);
var_dump($name); // null
var_dump($folder); // null
die;
}

Dont know why, Angular $http sends data as request body, JSON encoded whereas Symfony2 is reading $_GET and $_POST arrays.
So you got 2 solutions:
1- Update Php code, you could override SF2 Request class (https://gist.github.com/ebuildy/fe1e708e466dc13dd736)
2- Update Js code, you can "transform" the $http request (https://gist.github.com/bennadel/11212050)

A bundle has been created to solve this problem, and it's very light.
qandidate-labs/symfony-json-request-transformer

Related

unsupported media type application/x-www-form-urlencoded

I'm getting this error all of a sudden:
21:28:14.345 [debug] ** (Plug.Parsers.UnsupportedMediaTypeError) unsupported media type application/x-www-fo
rm-urlencoded
(plug) lib/plug/parsers.ex:231: Plug.Parsers.ensure_accepted_mimes/4
(api) lib/api/router.ex:1: Api.Router.plug_builder_call/2
(api) lib/plug/debugger.ex:123: Api.Router.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) /Users/Ben/Development/Projects/vepo/api/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
When making this network request:
Request URL:http://192.168.20.6:4000/products/?p_id=1&s_id=1
Request Method:PUT
Status Code:415 Unsupported Media Type
Remote Address:192.168.20.6:4000
Referrer Policy:no-referrer-when-downgrade
Response Headers
view source
cache-control:max-age=0, private, must-revalidate
content-length:45284
content-type:text/html; charset=utf-8
date:Sun, 28 Jan 2018 08:40:36 GMT
server:Cowboy
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-GB,en-US;q=0.9,en;q=0.8
Connection:keep-alive
Content-:application/json
Content-Length:75
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Host:192.168.20.6:4000
Origin:http://evil.com/
Referer:http://localhost:8081/debugger-ui/debuggerWorker.js
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
X-Requested-With:XMLHttpRequest
Query String Parameters
view source
view URL encoded
p_id:1
s_id:1
Form Data
view source
view URL encoded
s_id:1
p_id:1
image:null
price:2.53
description:kcucufufi icif Gigiuyub
Code to send the request:
import { ajax } from 'rxjs/observable/dom/ajax'
return ajax({
body: action.payload,
method: 'PUT',
headers: { 'Content-': 'application/json' },
url: `http://192.168.20.6:4000/products/?p_id=${
action.payload.p_id
}&s_id=${action.payload.s_id}`
}).map(response => updateEditProductInDbFulfilled(response))
.catch(error => Observable.of(updateEditProductInDbRejected(error)))
I didn't actively change anything in my backend to not accept x-www-form-urlencoded, so why would this happen when it used to work?
Is x-www-form-urlencoded bad? What is the best approach to successfully send my network request? Change my code sending the request or changing the backend somehow to accept the request?
Backend is Elixir.
This is how I added Plug.Parsers (In my router):
if Mix.env == :dev do
use Plug.Debugger
end
plug :match
plug Plug.Parsers, parsers: [:json],
pass: ["application/json"],
json_decoder: Poison
plug :dispatch

odata query works again ApiController but does not work again ODataController

I try use System.Web.OData.ODataController in WebAPI 2.
WebConfig.cs
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<User>("User");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel());
Controller:
public class UserApiODataController : ODataController
{
[Route("api/lookups/users")]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public IHttpActionResult GetUsers()
{
try
{
var context = new DbContenxt();
return Ok(context.Users.AsQueryable());
}
catch (Exception exception)
{
return InternalServerError(exception);
}
}
}
When I try query data I get error:
GET http://localhost:58786/api/lookups/users 406 (Not Acceptable)
When I replace ODataController with ApiController query works good.
Request Header:
Accept:application/atomsvc+xml;q=0.8, application/json;odata=fullmetadata;q=0.7, application/json;q=0.5, */*;q=0.1
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
DataServiceVersion:2.0
Host:localhost:58786
MaxDataServiceVersion:2.0
Origin:http://localhost:62131
Pragma:no-cache
Referer:htpp://localhost:62131/
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36
ODataController Response header:
Remote Address:[::1]:58786
Request URL:http://localhost:58786/api/lookups/users
Request Method:GET
Status Code:406 Not Acceptable
Response Headers
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://localhost:62131
Cache-Control:no-cache
Content-Length:0
Date:Mon, 30 Nov 2015 16:09:25 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/10.0
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?RDpccHJvamVjdHNcZG9rdW1lbnRhXFN3YWxsb3dcU3JjXFN3YWxsb3cuV2ViQXBpXGFwaVxsb29rdXBzXExpY2Vuc2VUeXBl?=
ApiController Response Header
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://localhost:62131
Cache-Control:no-cache
Content-Length:247
Content-Type:application/json; charset=utf-8
Date:Mon, 30 Nov 2015 16:20:53 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/10.0
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?RDpccHJvamVjdHNcZG9rdW1lbnRhXFN3YWxsb3dcU3JjXFN3YWxsb3cuV2ViQXBpXGFwaVxsb29rdXBzXExpY2Vuc2VUeXBl?=
On client side I use JayData.
What is wrong ? Any idea?
First, from the namespace System.Web.OData.ODataController, I think you are using the Web API OData V4 library. V4 doesn't accept application/atomsvc+xml because only "Json" is the standard in OData V4 spec.
Second, odata=fullmetadata is the OData V3 metadata header, for V4, it should be odata.metadata=full
Third, [Route("api/lookups/users")] is Web API attribute. If you want to use ODataController, please use the OData version. [ODataRoute("...")]
Fourth, please make sure the route template in [Route(...)] follows up the OData Uri conventions. See more detail here
Fifth, you can get more tutorial from here.
Hope it can help you. Thanks.

AngularJs - JSON post

I tried to post username and password to api, but looks like it doesnt work as simple as jquery post. I keep geting this 400 error.
Code:
$http({
method: 'POST',
url: apiLink + '/general/dologin.json',
data: {"username":"someuser","password": "somepass"}
}).success(function(response) {
console.log(response)
}).error(function(response){
console.log(response)
});
But if I add this line:
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
and change data to:
data: "username=someuser&password=somepass"
it works. But the thing is, that I have to use json.
And detailed informations from Google Chrome:
Request URL:http://coldbox.abak.si:8080/general/dologin.json
Request Method:POST
Status Code:400 Bad Request
Request Headersview source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en,sl;q=0.8,en-GB;q=0.6
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:57
Content-Type:application/x-www-form-urlencoded
Host:coldbox.abak.si:8080
Origin:http://localhost:8888
Referer:http://localhost:8888/
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36
Form Dataview sourceview URL encoded
{"username":"someuser","password":"somepass"}:
Response Headersview source
Access-Control-Allow-Origin:*
Connection:close
Content-Length:49
Content-Type:application/json;charset=utf-8
Date:Wed, 02 Apr 2014 07:50:00 GMT
Server:Apache-Coyote/1.1
Set-Cookie:cfid=b5bbcbe2-e2df-4eef-923f-d7d13e5aea42;Path=/;Expires=Thu, 31-Mar-2044 15:41:30 GMT;HTTPOnly
Set-Cookie:cftoken=0;Path=/;Expires=Thu, 31-Mar-2044 15:41:30 GMT;HTTPOnly
I'm betting it's a CORS issue if your angular app isn't on the exact same domain as the server to which you're posting your JSON.
See this answer for details: AngularJS performs an OPTIONS HTTP request for a cross-origin resource
Try
data: {username:"someuser",password: "somepass"}
without the quotes around the username and password and see if that makes a difference.
You would have to transform the data with a JSON.stringify when you assign that to the data

Please help me understand Ajax request versus Backbone fetch()

My app can currently hit our API with a standard JQuery Ajax GET request and get good data back. CORS has been properly implemented on the remote server as far as I can see. Here are the response headers:
company_client_envelope_id: 88764736-6654-22e4-br344-a1w2239a892d
access-control-allow-headers: X-Requested-With, Cookie, Set-Cookie, Accept, Access-Control
Allow-Credentials, Origin, Content-Type, Request-Id , X-Api-Version, X-Request-Id,Authorization, COMPANY_AUTH_WEB
access-control-expose-headers: Location
response-time: 55
request-id: 88764736-6654-22e4-br344-a1w2239a892d
company_api_version: 0.01.09
server: localhost
transfer-encoding: chunked
connection: close
access-control-allow-credentials: true
date: Sun, 09 Feb 2014 14:44:05 GMT
access-control-allow-origin: *
access-control-allow-methods: GET, POST
content-type: application/json
However, using Backbone and calling the same GET request by using fetch() causes the following CORS error:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
I cannot figure out what the difference is. Both requests are running from localhost.
In the case of the AJAX query, the following is being sent as requested by the API guys:
headers: {
"accept":"application/json"
}
And in the case of the model and collection declaration I am sending the headers like so:
MyApp.someCollection = Backbone.Collection.extend(
{
model:MyApp.someModel,
headers: {
'Accept':'application/json',
'withCredentials': 'true'
},
url: MYCOMPANY_GLOBALS.API + '/endpoint'
});
and my fetch is simply:
someCollection.fetch();
===============================
Added in response to: #ddewaele
These are the headers from the network tab:
Request URL:http://api-blah.com:3000/
Request Headers CAUTION: Provisional headers are shown.
Accept:application/json
Cache-Control:no-cache
Origin:http://localhost
Pragma:no-cache
Referer:http://localhost/blah/blah/main.html
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107Safari/537.36
There is no pre-flight or remote headers from the API server:
many thanks,
Wittner
I've recommended to you rewrite Backbone.sync method, because in your app you have some security field for example and other reason.
var oldBackboneSync = Backbone.sync;
// Override Backbone.Sync
Backbone.sync = function (method, model, options) {
if (method) {
if (options.data) {
// properly formats data for back-end to parse
options.data = JSON.stringify(options.data);
}
// transform all delete requests to application/json
options.contentType = 'application/json';
}
return oldBackboneSync.apply(this, [method, model, options]);
}
You can add different headers as you want.

Model Passed into MVC 4 Controller Null

I'm trying to serialize a form and pass it into a controller as a model. What I'm doing I've done in the past, but it's not working for some reason, so I suspect I am missing something stupid. Perhaps you can find it.
In my controller I have a method:
[HttpPost]
public ActionResult AddShippingLocation(PricingRequestModel model)
{
model.ShippingLocationsModel.Add(new ShippingLocationsModel());
return PartialView("shiplocationPartial", model);
}
In my view I have a script that looks like this:
function AddShippingLocation() {
$.ajax({
data: { model: $('#shippinginfoform').serialize() },
type: "POST",
url: "/PricingRequest/AddShippingLocation",
success: function (response) {
$('#shiplocation-wrapper').html(response);
}
})
}
This is called from a link that gets clicked. Also in the view I have a form that uses this:
#using (Html.BeginForm("AddShippingLocation", "PricingRequest", FormMethod.Post, new { id = "shippinginfoform" }))
{
I put the Addshippinglocation in as the method because I wanted to test to see if the model would be serialized using the built in helper. The model gets passed in properly using Html.BeginForm, it also gets passed in properly when using Ajax.BeginForm. When using jquery.serialize, though, it doesn't get passed in properly. On a side note, I'm using MVC 4. Any ideas? Thanks.
EDIT: Here's the request headers. The top one is a successful post of the model to the method, the bottom is the .serialize() that passes in a null model. I examined the post strings and the are the exact same.
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Connection keep-alive
Cookie .ASPXAUTH=9F06BF2A7D03211E0D2ACEC26D7A568754C89F8A265EE61D9F8010BB8DF1D97670212F1E853FDE960E87AAC5DC7D364A251F670560448482517DA7C072864F62AC0C5C3E1EE8D375ACC1EA8F4D63CFC3C1DD28BBDCAC945155D15289DCDDA3B540756C0609611C13A438B5FF4CA747219290AFB51F58B8AD35AE40C01D3AFAF8B32ADD7E200148B1E1646400CAC0F116; ASP.NET_SessionId=v3qwt02dn1pd13posl5zzk3n
Host localhost:2652
Referer http://localhost:2652/PricingRequest/custinfo
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:16.0) Gecko/20100101 Firefox/16.0
Request Headers From Upload Stream
Content-Length 471
Content-Type application/x-www-form-urlencoded
Accept */*
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Cache-Control no-cache
Connection keep-alive
Content-Length 555
Content-Type application/x-www-form-urlencoded; charset=UTF-8
Cookie .ASPXAUTH=9F06BF2A7D03211E0D2ACEC26D7A568754C89F8A265EE61D9F8010BB8DF1D97670212F1E853FDE960E87AAC5DC7D364A251F670560448482517DA7C072864F62AC0C5C3E1EE8D375ACC1EA8F4D63CFC3C1DD28BBDCAC945155D15289DCDDA3B540756C0609611C13A438B5FF4CA747219290AFB51F58B8AD35AE40C01D3AFAF8B32ADD7E200148B1E1646400CAC0F116; ASP.NET_SessionId=v3qwt02dn1pd13posl5zzk3n
Host localhost:2652
Pragma no-cache
Referer http://localhost:2652/PricingRequest/custinfo
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:16.0) Gecko/20100101 Firefox/16.0
X-Requested-With XMLHttpRequest
The request bodies are the same? Somehow, I'm doubtful.
Your ajax request body is going to have
model=....
where .... is your form serialized, which url encodes the inputs, and then the serialization itself is urlencoded. You're urlencoding twice with your ajax request. That doesn't happen with normal form posts, and urlencoding is not idempotent with respect to equal signs.
Try
data: $('#shippinginfoform').serialize(),
If the shippinginfoform form is the same form that's posted, I believe that should post the same data (well, generally: there may be some corner cases with values associated with submit buttons and such.).
I'll admit that there's some chance that I'm wrong, in which case I'll promptly delete this answer.

Resources