I have an ionic 3 project that allows for file upload to the server. The following code is working fine from Android. But on iOS it appears to get blocked (i.e. the server code at /upload.php is obviously the same in both cases, but coming from iOS it does not receive any of the posted data).
this.http.setDataSerializer('urlencoded');
this.http.post("http://example.com/upload.php", {
name: this.filename,
data: this.datafile
}, {"Content-Type":"multipart/form-data"})
.then(res => {
console.log('success response: ' + res.data);
}, error => {
console.log(error: ' + error);
});
Any ideas?
Is there some setting in xCode that needs to be configured to allow multipart/form-data posts to work? Or perhaps somewhere to white list the domain to allow it?
Turned out to be on the server side. Apparently PHP receives the post differently from Android as it does iOS. $_REQUEST["xxxx"] works fine for Android but in order to work for both it required this:
$postdata = file_get_contents("php://input");
parse_str($postdata, $param);
// then available as $param["xxxx"]
Thought I'd update the answer here in case anyone else bumps into this. Awfully obscure and took me days to figure out!
Related
Ionic Native HTTP returns {status: -1} for a single API call in IOS Simulator
I'm using Ionic Native HTTP to get around CORS issues in IOS and there's a single Wordpress API call /wp-json/wp/v2/ that is always returning -1, despite the fact that other /wp-json/wp/v2/ api calls work perfectly fine.
In addition, this works fine in Android, it's just IOS that's having issues.
HTTP Code where http = #ionic-native/http/ngx
const url = https://example.com/wp-json/wp/v2/data?order=asc&order_by=id&per_page=100&after=2020-07-30 00:00:00&before=2020-07-30 23:59:59;
this.http.get(url, {}, {})
.then((data) => {
console.log('returning data');
console.log(data);
})
.catch((err) => {
console.log('erroring');
console.log(err);
console.log(err.status);
console.log(err.error); // error message as string
console.log(err.headers);
});
There's nothing special about this code, it's just a single Wordpress API call, but I always get -1 returned. This question states it's a CORS issues, where pre-flight OPTIONS requests get rejected, but the entire point of Native HTTP was to avoid CORS as I cannot modify the server.
Has anyone else encountered and fixed this status -1 issue?
EDIT
See my answer below.
The issue was the space in the URL, it seems that Android and browsers automatically replace the space with %20, but IOS does not.
Thus the new URL should be as below and that now works fine.
const url = https://example.com/wp-json/wp/v2/data?order=asc&order_by=id&per_page=100&after=2020-07-30%2000:00:00&before=2020-07-30%2023:59:59;
I'm using react-native-image-picker (^0.28.0) along with rn-fetch-blob (^0.10.15).
It works so far when using a Simulator, but when I use it on real iPhone, the image isn't uploading, it fails to upload with the following error that is being catched by the promise.
"Error: Could not connect to the server."
(Yes, server is up and running)
If you see this, you might think it's a backend issue but other requests work fine on real device, this one is the only having problems. The image request being sent is this one:
{
data: "RNFetchBlob-file:///var/mobile/Containers/Data/Application/843A96A1-0000-40D3-B50F-95D69B94B87A/tmp/5D22283B-2014-4E9E-AC3E-AE677D91A366.jpg"
filename: "IMG_6834.jpg"
name: "pictures"
type: "image/jpeg"
}
The only difference with the simulator device and my iPhone is the data path. Where on simulator is like "RNFetchBlob-file:///Users/marian-mac/Library/Developer/CoreSimulator/Devices/....etc"
Any idea why should be different from the simulator on this? It seems to be sending the same request.
Some extra info, when I preview the image in an Image component, it shows well too. So it seems the path is correct on the real iPhone.
This is the method to upload image
uploadPicture: function(data, token) {
return RNFetchBlob.fetch('POST', Constants.baseUrl + '/picture', {
Authorization: "Bearer " + token,
'Content-Type': 'multipart/form-data;boundary=***BOUNDARY***'
}, data);
},
And this is how I build the picture request array, this.state.images contains the image-picker data.
this.state.images.forEach((image) => {
reqData.push({
data: image.imageFile,
filename: image.fileName.split('.')[0] + '.jpg',
name: 'pictures',
type: image.type
})
});
The problem could be that you are uploading to a non-https url. Had this same issue and the nsAllowArbitraryLoads made it work on simulator and gave error when using it on a real device.
Had to wait until it became https
It does not seem to be the problem with http or https. (mine is http)
I'm having a file on this path:
filepath =/var/mobile/Containers/Data/Application/F8F06A2A-C04D-4B6D-A316-F879E144366B/Documents/test.wav
I tried RNFetchBlob.wrap(filePath) but no use.
So I tried to add this file to the asset of ios project and using RNFetchBlob.wrap(RNFetchBlob.fs.asset('test.wav')). Voila, it works.
As a result, it seems to be the problem with filepath
After searching now for hours, I unfortunately can't find a solution to my current iOS Safari issue.
I've got a JavaScript frontent which uses jQuery.ajax to communicate with an ASP.NET MVC web server.
That works absolutely perfect on all platforms, e.g. Windows 10 with Chrome, Firefox, IE (yes, IE works), Edge. Or on a Mac with Chrome, Firefox, Safari. The place where it does not work is iOS Safari.
In my scenario, I'm sending multiple AJAX requests to the server almost at the same time. Maybe 3 to maximum 6 calls. Having a look at the Safari developer tools, the calls look like this.
They seem to take very long, but having a look at the server, they appearently never reach the backend. Also, after exactly 10 minutes, the browser runs into the timeout. Even though I have configured an AJAX timeout of 60 seconds.
My code looks pretty okay to me at the moment (written in TypeScript):
let defer: JQueryDeferred<any> = jQuery.Deferred();
this._RunningRequests++;
let settings: JQueryAjaxSettings = {
method: method,
url: this.BuildURL(controller, action, id),
contentType: 'application/json',
timeout: Timeout,
cache: false,
headers: {}
};
if (payload) {
settings.data = JSON.stringify(payload);
}
jQuery.ajax(settings)
.done((result: any) => {
if (this.DetectLogoutRedirect(result)) {
defer.reject();
location.reload(true);
return;
}
defer.resolve(result);
})
.fail((jqXHR: JQueryXHR, textStatus: string, errorThrown: string) => {
defer.reject();
this.HandleError(method, controller, action, jqXHR, textStatus, errorThrown);
}).always(() => {
this._RunningRequests--;
});
return defer.promise();
Here now the fun part. As soon as I add a delay to the call ...
let delay = this._RunningRequests * 500;
setTimeout(() => { jQuery.ajax(...) }, delay);
... which makes sure the calls are not sent quickly after each other, it works perfectly fine.
Things I've tried and found out so far:
I've set all headers for cache control plus all jQuery configurations adressing cache to false
I've added a guid-like param to every call (POST as well) to ensure the URL is always unique
As mentioned above, I've added the delay which solves the problem, but is not realy practiable
I've tried to reproduce the issue wihin the iOS Simulator. Same result.
It seems to affect POST requests only, but I'm not sure about that.
How can I fix this?
We encountered the same issue with our Single Page App as soon as it got particulary "chatty" with our API.
It appears to be caused by a bug with the DNS resolution somewhere in the iOS networking stack.
We found that by changing the DNS setting from automatic to manual on the device, and setting the DNS servers to the Google Public DNS, all XHR requests made by our app worked and we stopped getting the weird timeouts.
Here is a guide on how to change the DNS setting on an iOS device:
https://www.macinstruct.com/tutorials/how-to-change-your-iphones-dns-servers/
I have an app written in HTML5, Javascript, css3 using PhoneGap to compile for iOS and Android. It collects survey information and uploads this via Ajax call to online host. It has been working really well until recently the upload code appeared to stop working. WELL NOT QUITE! On the iPad it says successful but in fact nothing ever makes it to the host. This is VERY strange. I've tried re-writing the Ajax call based on articles on here but no luck.
iOS - 6.1.3, PhoneGAP 2.7.0, PhoneGap/Adobe Build used.
This is the upload piece...
function sendToWeb(){
var errorflag = false;
db.transaction(function (tx) {
tx.executeSql("SELECT weburl FROM settings", [], function(tx, results){
var webURL = results.rows.item(0).weburl;
tx.executeSql("SELECT * FROM surveypretransfer WHERE uploaded = '0'",[], function(tx, results){
if (results.rows.length == 0) {
alert("You have no surveys waiting to upload");
} else {
alert("You have " + results.rows.length + " surveys waiting to upload");
for (var i=0; i < results.rows.length; i++) {
var responseURL = webURL + "/feeds/saveinfo.php";
var responseString = results.rows.item(i).responsestring;
var localid = results.rows.item(i).id;
//alert(localid);
$.ajax({
type: 'POST',
data: responseString,
url: responseURL,
timeout: 30000,
success: function(data) {
alert('Success!' + data.join('\n'));
},
error: function(data) {
alert(data.join('\n'));
console.log("Results: " + localid);
alert("Error during Upload. Error is: "+ data.statusText);
}
}); //ajax
}; //for loop
alert("You have successfully uploaded "+ results.rows.length + " survey results");
tx.executeSql("UPDATE surveypretransfer SET uploaded = '1' WHERE uploaded = '0'");
}; //if statement
}); //tx.execute
});
}, errorCB);
}
Neither of the two alerts fire when loaded on iPad. Works fine on Android and has previously worked on iPad so I can't find what has changed.
UPDATE: Appears that this only applies to WiFi only iPads. All the 3G ones I tested were fine. Figure that!
Config.XML contains app id = "com.mydomain.myapp" (as an example)
URL for upload is "http://customer.mydomain.com/feeds/saveinfo.php?..."
Also added line 'access origin="http://mydomain.com" subdomains="true" '
Still no results. Is anyone seeing/having similar issues? Anyone see my mistake?
For iOS you might want to try <access origin="http://*.mydomain.com" />, as iOS is not documented in the PhoneGap API to support the subdomain property.
If that doesn't solve your issues, you will probably want to look into CORS (Cross Origin Resource Sharing). I had issues trying to do a POST request from my app to a local port on iOS. The W3C has a great article on how to enable CORS that will probably help. I know in my case, the system would attempt to do an OPTIONS request first, and if it didn't work, the whole thing would fail.
Another tool that you will probably find useful (if not now, in the future) is Fiddler. You can set up an iPad to proxy through your desktop, and then you will be able to observe all of the requests going to and from the device. This is how I found the OPTIONS request noted above.
i've got an android app and a really simple web service that make an insert in a DB with 3 values.
the titanium code is most like the example given on the docs
var xhr = Ti.Network.createHTTPClient();
xhr.onload = function(e) {};
xhr.open('POST','http://www.micheleantonaci.altervista.org/test/foobar.php');
xhr.send({
"latitude":00100,
"longitude":10000,
"type":'From Nexus'
});
and the web service is just
<?php
$con=mysql_connect('http://www.micheleantonaci.altervista.org/','***','***');
mysql_select_db('***',$con);
if(isset($_REQUEST['submit']))
{
$latitude=$_POST['latitude'];
$longitude=$_POST['longitude'];
$kind=$_POST['type'];
$sql="insert into foobar (latitude,longitude,type) values ('$latitude','$longitude','$kind')";
$res=mysql_query($sql) or die (mysql_error());
}
?>
now, when i try the webservice giving the values with the browser it works good, but with the app I get no results at all, any suggestions? tha app doesn't crash or log any error
You must use PHP function json_decode to get values.
Try adding the header like this:
xhr.setRequestHeader("Content-Type", "application/json");
You should also do a var_dump($_POST) in your PHP to see what's in it, not sure you'll get your stuff in separated variables...
When I see a problem like this, I setup 'Charles' or a similar proxy and have the device send it's request through the proxy. Then you can see if the device is send what is expected.
You could also try
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
The code is right, the problem was on the framework itself, at that day the post method wasn't working.
Nowadays it has been fixed.