Cross-domain AJAX POST request works perfectly fine on web browsers including browsers on mobile phones, but doesn't work for native applications built using Phonegap
I have created a login form that users have to enter their login credentials, then they are verified by the server that is hosted on heroku and returns json {"success":true} if valid credentials are entered.
My Ajax script:
$.ajax({
type: "POST",
url: "http://domain.com/public/auth/app-login",
contentType: "application/x-www-form-urlencoded; charset=utf-8",
dataType: "json",
data: {identity: <username from form>, password: <password from form>},
crossDomain: true,
cache: false,
success: function(data) {
obj = JSON.parse(data);
if (obj && obj.success === true) {
window.location.href = 'home.html';
}
},
error: function(e) {
alert('Error: ' + e.message);
}
});
Steps taken to resolve this issue:
Domain whitelisting - config.xml
<access origin="http://domain.com/public/auth/app-login" />
<access origin="*" />
Telling jQuery to allow cross-domain
$.support.cors = true;
OR
jQuery.support.cors = true;
Disable caching cache: false
Any help is appreciated.
Ok. If index.html in local then you can call ajax any hosts, not need enable CORS in client or server. You remove:
$.support.cors = true; OR jQuery.support.cors = true;
And:
<access origin="http://domain.com/public/auth/app-login" />
It redundant, only use:
<access origin="*" />
You need check and add in AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
Add more permission if your app required. Finally, call ajax inside $(document).ready():
$.ajax({
type: "POST",
url: "http://domain.com/public/auth/app-login",
dataType: "json",
data: {identity: <username from form>, password: <password from form>},
success: function(data) {
obj = JSON.parse(data);
if (obj && obj.success === true) {
window.location.href = 'home.html';
}
},
error: function(e) {
alert('Error: ' + e.message);
}
});
If you are looking to resolve this issue then you may wish to make sure that the plugin is being properly included into the build process.
RESOURCE: \app\config.xml
<widget>
.... [lots of stuff] ....
<gap:plugin name="com.indigoway.cordova.whitelist.whitelistplugin" />
<access origin="http://*" />
....
</widget>
You may also wish to specify a version as that is recommended, and I do not specify one above. A good way to test if the plugin is included is to use the free cloud account provided at, https://build.phonegap.com/apps. If you build your project there you can check the plugins tab and make sure that the whitelist plugin is included.
I have read that you should only need this in the HEAD element of your HTML page, but I found as of the date of this post that I still needed to include the plugin.
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
If the plugin is not loaded you might get a "Not Found" error when using the $.ajax method for jQuery for the error string.
Some of the information on the Internet will tell you that the whitelist information is placed into the /www/res/ folder, but this appears to be outdated information. You may also find that <plugin... is used in some examples, but it appears that this may be an obsolete way?
Also, you may need:
RESOURCE: \app\config.xml
<widget>
...
<feature name="http://api.phonegap.com/1.0/network"/>
...
</widget>
use
JSON.stringify(data: {identity: <username from form>, password: <password from form>})
instead of
data: {identity: <username from form>, password: <password from form>}
I got success message when i changed my code like this.
Some time there is issue in your domain. In my case I resolved it by putting following code in my .htaccess file
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
Related
We are building an app which requires an API request.
On front end we are using Ionic with Angular. When we tried to send a request to backend we get this error.
It works when we are trying on desktop in browser.
{
"headers":{
"normalizedNames":{
},
"lazyUpdate":null,
"headers":{
}
},
"status":0,
"statusText":"Unknown Error",
"url":"http://server_ip:3000/path/useCode/1234",
"ok":false,
"name":"HttpErrorResponse",
"message":"Http failure response for http://server_ip:3000/path/useCode/1234: 0 Unknown Error",
"error":{
"isTrusted":true
}
}
This is how we send a request.
import { HttpClient, HttpHeaders } from '#angular/common/http';
public sendCodeGET() {
this.httpClient.get(`http://server_ip:3000/path/useCode/${this.code.trim()}`).subscribe(
res => {
this.response = JSON.stringify(res);
},
err => {
this.response = JSON.stringify(err);
this.presentToast(err.error['message']);
}
);
}
We are using NodeJS v10.15.3 where we set CORS header presented below.
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, Authorization");
res.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS, DELETE");
res.setHeader("Access-Control-Expose-Headers","Content-Length,Content-Range");
if (req.method === 'OPTIONS') {
res.setHeader('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
return res.status(200).json({});
}
next();
});
config.cml
<access origin="*" />
<allow-navigation href="*" />
<allow-intent href="*" />
index.html
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
We have also tried:
- other API (https://coinmarketcap.com/api)
- POST and GET requests
I faced the same issue, but i sorted it as below. Follow these steps
Open [yourProject]/android/app/src/main/AndroidManifest.xml
2.Add this line there android:usesCleartextTraffic="true"
3.Add this line to config.xml file
<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application" xmlns:android="http://schemas.android.com/apk/res/android">
<application android:usesCleartextTraffic="true" />
</edit-config>
Some things I would suggest trying;
Download a CORS plugin that can allow you to bypass blocked headers
If you're using ionic I am assuming that this if for a hybrid app. Make use of ionic HTTP. You could get better results.
Check out Ionic's official docs for some help https://ionicframework.com/docs/troubleshooting/cors
I'm using ionic 2 framework to develop an application and encountered a weird problem.
I'm using HTTPS to communicate to my webservice and Android 5 mobile is throwing me No Access-Control-Allow-Origin header problem while Android 6 works fine by returning me a result.
Upon inspection this might be something to do with CORS and 'Access-Control-Allow-Origin' header not present in the server config.
Android 5 HTTPS request header
Android 6 HTTPS request header
This is my content security policy at phone side:
<meta http-equiv="Content-Security-Policy" content="default-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval' *; style-src 'self' 'unsafe-inline' *">
This is my function for https:
webserv()
{
var request = require('request');
return new Promise(function(fulfill, reject) {
request({
url: 'https://address,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {}
}, function(error, response, body) {
if (error) {
// reject the promise, handle with .catch
console.log("Error: "+error);
reject(error);
} else {
console.log(response.statusCode, body);
fulfill(body);
}
});
});
}
This is the error message
I'm guessing it's due to the origin is "file://" in the HTTP headers which is causing the problems.
I do not wish to change my server config if possible. And as this only affects Android 5 for me, I'm pretty confused in which where did I done wrongly.
Update:
Ran a couple of tests with other mobile phones and found out that I'm only able to support Android 5.1.1 and above. Version 5.0.1 (which is the original phone in this question) is unable to support still.
Update2:
Enabled CORS in server config and apparently it works for Android 5.0.1 . But still do not know the underlying cause.
I have a problem and I don't know how fix it.
I has $http.get() in Ionic and when I do ionic serve it works perfect. But when I run ios/android or I see it in Ionic View nothing happens.
My Service:
.service('myService', function($rootScope, $http, $q) {
this.all = function() {
var deferred = $q.defer();
$http.get('xxxxxxxxxxxxxxx')
.success(function(data) {
deferred.resolve(data);
})
.error(function(data) {
alert(data);
deferred.reject(data);
});
return deferred.promise;
};
});
And in my Controller:
myService.all().then(function(data) {
$scope.data = data;
});
When I open in a browser it shows good, and in devices I get the alert with "null".
I do:
Ionic update
Install cordova-plugin-whitelist
Ionic build ios/android -> ionic upload / ionic run
add:
<access origin="*" subdomains="true"/>
<allow-navigation href="http://*/*"/>
in config.xml
But nothing work... Any idea?
Thanks so much.
I tried with every site and nothing. It's weird
Update: I add
<meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-eval' 'unsafe-inline'">
And the same thing
I'm trying to do SSL pinning with Cordova 5.3.3 and Android with the following plugin:
https://github.com/wymsee/cordova-HTTP
When I enable the pinning with the following funcion and I do the GET it throws me an Error 500: "There was an error with the request". (All tests are done inside the android device using the inspector).
window.cordovaHTTP.enableSSLPinning(
true,
function(res) {console.log("SSL pinning: " + res)},
function(err) {console.log("SSL pinning: " + err)}
);
window.cordovaHTTP.get(
"https://95.85.12.4/test.json",
{}, // optional params
{}, // optional headers
function(res) {console.log(res)},
function(err) {console.log(err)}
);
If I accept all certs everything works fine due the fact that I'm overlapping the configuration of the pinning.
window.cordovaHTTP.enableSSLPinning(
true,
function(res) {console.log("SSL pinning: " + res)},
function(err) {console.log("SSL pinning: " + err)}
);
window.cordovaHTTP.acceptAllCerts(
true,
function(res) {console.log('Accept all certs: ' + res)},
function(err) {console.log('Accept all certs: ' + err)}
);
window.cordovaHTTP.get(
"https://95.85.12.4/test.json",
{}, // optional params
{}, // optional headers
function(res) {console.log(res)},
function(err) {console.log(err)}
);
I'm doing this tests in my server running NGINX. https://95.85.12.4/test.json
I white-listed everything (just for testing purposes)
<!-- Enable all requests, inline styles, and eval() -->
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
I also set the debuggable variable into the AndroidManifest.xml to true.
<application android:debuggable="true">
My certificate is self-signed with DER format and .cer extension.
I checked that the certificate is correct with openssl.
If I install the certificate in my machine there's no problem opening the server URL with
the browser.
The certificates are located into the /www/certificates folder inside my Cordova project.
I also added the .cer insinde /platforms/android/assets.
Any idea?
Thanks!
The problem is not related to the certificate format. It is because of the IP address. You need to create a certificate with SubjectAltName (SAN) as described here if you are not using host name to send a request. You have to write the IP address as an alt_name. Otherwise you get a "Hostname xxx.xxx.xxx.xxx not verified" error.
Using PhoneGap 2.5.0 + jQuery 1.9.1 + jQueryMobile 1.3.0, I'm trying to download a remote JSON file:
$(document).ready(function() {
$.getJSON("http://foo.mydomain.com/json.php?callback=?",function(data) {
alert("It works");
})
});
I modified 'res/xml/config.xml' to allow remote accesses to my server:
<cordova>
<access origin="http://127.0.0.1*"/>
<access origin="http://foo.mydomain.com*" />
<content src="index.html" />
But it does not work. What am I doing wrong? Thank you very much in advance.
Probably it's a problem related with Access-Control-Allow-Origin Issue.
To solve this, you should use JSON-P in the ajax request.
Try something like this:
$.ajax({
type : "GET",
dataType : "jsonp",
url : 'your-external-url',
data : {},
success: function(obj){
}
});