9

I'm building a Cordova APP with simple REST calls.

The issue is when I make a AJAX with POST, Chrome sends me: "XMLHttpRequest cannot load http://192.168.1.111/project/app. Response for preflight has invalid HTTP status code 405" on console.

But, if I make a AJAX call with GET (basically return an value from database) the things works like a charm.

My AJAX call is:

$.ajax({
  url: "http://192.168.1.111/project/app",
  type: "POST",
  dataType: "json",
  contentType: 'application/json',
  data: {
    "name": "Cordova"
  },
  success: function() {
    navigator.notification.alert("Success!");
  },
  error: function(jqXHR, textStatus, errorThrown) {
    console.log(textStatus + jqXHR.responseText);
  }
});

POST handler in REST

require 'Slim/Slim.php';
$app = new Slim();
$app->post('/app', 'addApp');
$app->run();

function addApp() {
    error_log('addApp\n', 3, '/var/tmp/php.log');
    $request = Slim::getInstance()->request();
    $callback = json_decode($request->getBody());
    $sql = "INSERT INTO app (name) VALUES (:name)";
    try {
        $db = getConnection();
        $stmt = $db->prepare($sql);  
        $stmt->bindParam("name", $callback->name);
        $stmt->execute();
        $callback->id = $db->lastInsertId();
        $db = null;
        echo json_encode($callback); 
    } catch(PDOException $e) {
        error_log($e->getMessage(), 3, '/var/tmp/php.log');
        echo '{"error":{"text":'. $e->getMessage() .'}}'; 
    }
}

function getConnection() {
    $dbhost="localhost";
    $dbuser="myuser";
    $dbpass="mypass";
    $dbname="mydb";
    $dbh = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);  
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $dbh;
}

What i've tried:

1#: Access origin in config.xml

<access origin="*" />

2#: Add the connect-src MY IP to meta tag

<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; connect-src 'self' http://192.168.1.111">

3#: Add Access-Control-Allow-Origin in my REST app .htaccess

Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT"

4#: Add support cors in JavaScript

$.support.cors = true;
$.mobile.allowCrossDomainPages = true;

5#: To check if is not error in Server POST, I used CURL and works normal (success)

curl -i -X POST -H 'Content-Type: application/json' -d '{"name": "Cordova"}' http://192.168.1.111/project/app

OBS: I'm using Slim framework to REST (http://coenraets.org/blog/2011/12/restful-services-with-jquery-php-and-the-slim-framework/)

================

Update #1:

I've upload my database and application to an online host and the results still the same.

================

Update #2:

Doing another tests, I noticed that removing the contentType: "application/json" the debugger shows another error.

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be empty

================

It's been two days that I'm trying to resolve this and nothing appears as a solution. I'm really sad.

reidark
  • 870
  • 4
  • 11
  • 22
  • You server not support post, you can show you action code? – Naumov Feb 27 '16 at 21:27
  • @Naumov Sorry, I forgot that point, I've updated my question. The server POST is working, I've used CURL to test it. – reidark Feb 27 '16 at 21:48
  • I think maybe this help you http://stackoverflow.com/questions/298745/how-do-i-send-a-cross-domain-post-request-via-javascript and `url: "http://192.168.1.111/project/app"` try url with out shema `http://` – Naumov Feb 27 '16 at 21:53
  • @Naumov I've tried to delete the *http://*, but not work (didn't find the url). And some solutions from this link not seems to work too. – reidark Feb 28 '16 at 16:14
  • strangle you look post request send in your browser? – Naumov Feb 28 '16 at 16:40
  • did you try with OPTIONS instead of POST? Some javascript frameworks perform two requests (hence the pre-flight check) – Terry Kernan Feb 29 '16 at 20:31
  • @TerryKernan Thank you for comment. I've tried to change POST to OPTIONS in AJAX call, but the error still the same. – reidark Feb 29 '16 at 20:55
  • @reidark do you have a POST handler in your app?, it looks like is not a CORS problem. – Sebastián Espinosa Feb 29 '16 at 21:50
  • @SebastiánEspinosa Yes, my REST api in based on link I've pasted on my question (http://coenraets.org/blog/2011/12/restful-services-with-jquery-php-and-the-slim-framework/) and I've tested with CURL the POST method. – reidark Feb 29 '16 at 21:58

2 Answers2

1

I think the problem may be this:

the preflight error is due to the fact that the client is making a OPTIONS request (before the post); this request is not handle correctly by the server. Since the OPTIONS request is not handled by the server the next POST is not processed. So first of all check with the debugger (or sniffing on the server) which is the request that is causing the error you mention. If my guess is right handle it and you will see that the next POST will be excuted correctly by the client.

pinturic
  • 2,253
  • 1
  • 17
  • 34
0

After reading about 60 questions in StackOverflow and things about CORS, PHP and Access Control I reach a "simple solution".

But, before I post the solution, I want to say that type of problem is too much "general" and the error can be anywhere.

Ok, first, the solution doesn't work on Chrome. Chrome will always returns the 405 status code, but, running the cordova app in real devices (or simulators) the solution works like a charm. Yes, this is about Chrome blocking cross-domain requests.

First step:

The data in AJAX must be placed with '{}'. Yes, I didn't knew about that. If you need, play around JSON.stringify to make much easier.

$.ajax({
    url: "http://myonlineurl.com/project/app",
    type: "POST",
    dataType: "json",
    contentType: 'application/json',
    data: '{ "name": "Cordova", "another_thing" : "thing" }',
    success: function() {
        navigator.notification.alert("Success!");
    },
    error: function(jqXHR, textStatus, errorThrown) {
        console.log(textStatus + jqXHR.responseText);
    }
});

Second step:

In REST API you need to enable the Access-Control-Allow-Headers for things work.

<?php header('Access-Control-Allow-Headers: X-Requested-With, origin, content-type'); ?>

At the present moment my APP is working normal with these solutions. I'm glad to hear about other solutions (for work in Chrome too).

Thank you guys!

reidark
  • 870
  • 4
  • 11
  • 22