Viewed   210 times

I know there are a lot of questions like this, but none I've seen have fixed my issue. I've used at least 3 microframeworks already. All of them fail at doing a simple POST, which should return the data back:

The angularJS client:

var app = angular.module('client', []);

app.config(function ($httpProvider) {
  //uncommenting the following line makes GET requests fail as well
  //$httpProvider.defaults.headers.common['Access-Control-Allow-Headers'] = '*';
  delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

app.controller('MainCtrl', function($scope, $http) {
  var baseUrl = 'http://localhost:8080/server.php'

  $scope.response = 'Response goes here';

  $scope.sendRequest = function() {
    $http({
      method: 'GET',
      url: baseUrl + '/get'
    }).then(function successCallback(response) {
      $scope.response = response.data.response;
    }, function errorCallback(response) { });
  };

  $scope.sendPost = function() {
    $http.post(baseUrl + '/post', {post: 'data from client', withCredentials: true })
    .success(function(data, status, headers, config) {
      console.log(status);
    })
    .error(function(data, status, headers, config) {
      console.log('FAILED');
    });
  }
});

The SlimPHP server:

<?php
    require 'vendor/autoload.php';

    $app = new SlimSlim();
    $app->response()->headers->set('Access-Control-Allow-Headers', 'Content-Type');
    $app->response()->headers->set('Content-Type', 'application/json');
    $app->response()->headers->set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    $app->response()->headers->set('Access-Control-Allow-Origin', '*');

    $array = ["response" => "Hello World!"];

    $app->get('/get', function() use($array) {
        $app = SlimSlim::getInstance();

        $app->response->setStatus(200);
        echo json_encode($array);
    }); 

    $app->post('/post', function() {
        $app = SlimSlim::getInstance();

        $allPostVars = $app->request->post();
        $dataFromClient = $allPostVars['post'];
        $app->response->setStatus(200);
        echo json_encode($dataFromClient);
    });

    $app->run();

I have enabled CORS, and GET requests work. The html updates with the JSON content sent by the server. However I get a

XMLHttpRequest cannot load http://localhost:8080/server.php/post. Response for preflight has invalid HTTP status code 404

Everytime I try to use POST. Why?

EDIT: The req/res as requested by Pointy

 Answers

5

EDIT:

It's been years, but I feel obliged to comment on this further. Now I actually am a developer. Requests to your back-end are usually authenticated with a token which your frameworks will pick up and handle; and this is what was missing. I'm actually not sure how this solution worked at all.

ORIGINAL:

Ok so here's how I figured this out. It all has to do with CORS policy. Before the POST request, Chrome was doing a preflight OPTIONS request, which should be handled and acknowledged by the server prior to the actual request. Now this is really not what I wanted for such a simple server. Hence, resetting the headers client side prevents the preflight:

app.config(function ($httpProvider) {
  $httpProvider.defaults.headers.common = {};
  $httpProvider.defaults.headers.post = {};
  $httpProvider.defaults.headers.put = {};
  $httpProvider.defaults.headers.patch = {};
});

The browser will now send a POST directly. Hope this helps a lot of folks out there... My real problem was not understanding CORS enough.

Link to a great explanation: http://www.html5rocks.com/en/tutorials/cors/

Kudos to this answer for showing me the way.

Thursday, October 20, 2022
2

The following solution worked:

Within filters.php add the following:

App::before(function($request)
{
    if (Request::getMethod() == "OPTIONS") {
        $headers = array(
            'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE',
            'Access-Control-Allow-Headers'=> 'X-Requested-With, content-type',);
        return Response::make('', 200, $headers);
    }
});

And at the top of routes.php add the following:

header('Access-Control-Allow-Origin: http://app.mydomain.io');

Thanks to the Google Plus community! :)

Leon.

Wednesday, September 14, 2022
 
4

I finally found a work around. what i did is i removed custom headers from web.config file. i.e,

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*"/>
    <add name="Access-Control-Allow-Headers" value="Origin, Content-Type, X-Auth-Token"/>
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    <add name="Content-Type" value="application/json"/>

    <add name="Access-Control-Allow-Credentials" value="true" />
  </customHeaders>
</httpProtocol>

This content i removed

and in WebApiConfig.cs i did following changes

var enableCorsAttribute = new EnableCorsAttribute(origins:"*",headers:"*",methods:"*");

            var json = config.Formatters.JsonFormatter;

            json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
            config.Formatters.Remove(config.Formatters.XmlFormatter);

            config.EnableCors(enableCorsAttribute);

and Controller Looks like this.

[EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)]
    [RoutePrefix("api/Add_Client_")]
    public class Add_Client_Controller : ApiController
    {
[AcceptVerbs("POST")]

        [HttpPost]
        [Route("PostGoals")]
        public string PostGoals(string goal)
        {
            Goal g = new Goal();
            g.Goals = goal;
            db.Goals.Add(g);
            int res = db.SaveChanges();

            return ("Success");
        }
}

and Angular POST Method looks like following

 save_Goals(){

  let headers : Headers= new Headers();
        headers.append('Content-Type','application/x-www-form-urlencoded');
    headers.append('Access-Control-Allow-Origin','*');
      headers.append('Access-Control-Allow-Methods','GET,PUT,POST,DELETE');
      headers.append('Access-Control-Allow-Headers','Content-Type');

      let options = new RequestOptions({ headers: headers });
    return this._http.post('http://localhost:49975/api/Add_Client_/PostGoals?goal=check',options)
       .map(res =>  res.json());
    }

This is work around to send data with URL.

Sunday, October 23, 2022
 
3

@Rakeschand you were right and it was the issue of cors

Cors

I installed Cors in my project using nu-get command line

Install-Package Microsoft.AspNet.WebApi.Cors

and added the follwoing code in WebApiConfig.cs file from App_Start folder.

var enableCorsAttribute = new EnableCorsAttribute("*",
                                               "Origin, Content-Type, Accept",
                                               "GET, PUT, POST, DELETE, OPTIONS");
config.EnableCors(enableCorsAttribute);

and removed the following from the web config

   <remove name="X-Powered-By" />
                    <add name="Access-Control-Allow-Origin" value="*" />
                    <add name="Access-Control-Allow-Headers" value="Accept, Content-Type, Origin" />
                    <add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, OPTIONS" />

$http started working just like the $.ajax was working

but these things left me with some confusion. I would be great full if anyone can elaborate

  1. why the $.ajax was working and $http was not working
  2. I did the same thing by cors the I had done in web.config then why did cors worked but web.config didn't?
Saturday, November 12, 2022
3

Just add the data to send:

$http({
        method:"POST",
        url:"files.php",
        data: {
          "id": id
        },
        headers:headers
      })

And change your header in order to set as content: application/json

Thursday, December 8, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :