Cordova AJAX POST permission

12,372

Solution 1

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!

Solution 2

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.

Share:
12,372
reidark
Author by

reidark

Updated on July 26, 2022

Comments

  • reidark
    reidark almost 2 years

    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
    reidark about 8 years
    Yes, in debugger the OPTIONS appears before the main error. But, i don't know what exactly is this.
  • pinturic
    pinturic about 8 years
    Perfect! You have to handle the OPTIONS request on the server.