Error while using superagent in react native ios app - ios

i have made a react native app that used nodejs and express for backend, have cors enabled and which running on android but when i started porting the app for ios and run it in simulator iphone 6, it is running fine but when it comes to hit an api for that i used superagent give me this error.
Error: Request has been terminated
Possible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.
at Request.crossDomainError (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:80241:9)
at XMLHttpRequest.xhr.onreadystatechange (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:80311:13)
at XMLHttpRequest.dispatchEvent (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:10000:15)
at XMLHttpRequest.setReadyState (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:26063:6)
at XMLHttpRequest.__didCompleteResponse (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:25917:6)
at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:26011:52
at RCTDeviceEventEmitter.emit (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:9233:23)
at MessageQueue.__callFunction (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:7213:34)
at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:7104:8
at guard (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:7050:1)
this is how i use superagent
const request = require('superagent');
const req = request[options.method.toLowerCase()](options.uri)
.set(merge({}, options.headers, options.json ? {'Content-Type': 'application/json'} : {}))
.query(options.qs ? options.qs : {})
.send(options.json || options.form || options.formData)
;
const requestId = {};
api.activeRequests.add(requestId);
return new Promise((resolve, reject) => {
req.end((err, res) => {
console.log({err, res});
api.activeRequests.delete(requestId);
if (err || !res.ok) {
console.log(res);
const error = res ? (res.body ? res.body : res) : err;
reject(error);
} else {
resolve(res.body);
}
});
});
Need help!

It was due to https request to be posted not http. So as of now since i am in developer mode allowed http to my particular domain.

Related

Supabase Auth - redirectTo not working for OAuth

I am switching from Flutter to Supabase and am running into an issue with Authentication. Although I can successfully launch the URL with the correct redirect value, I keep getting redirected to the site URL which should only be used for web, not iOS or Android. Below is the function I am using for Apple but this is happening with all other providers as well.
const isWeb = Platform.OS === "web";
const redirectTo = isWeb
? "https://web.example.com/login-callback/"
: "com.example.react://login-callback/";
export const signInWithApple = async () => {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "apple",
options: {
redirectTo: redirectTo,
},
});
if (error !== null) {
console.log(error?.message);
return "error";
} else {
console.log(data);
Linking.openURL(data.url);
return "success";
}
};
The URL that gets logged before launching is correct, for example, LOG {"provider": "apple", "url": "https://api.example.com/auth/v1/authorize?provider=apple&redirect_to=com.example.react%3A%2F%2Flogin-callback%2F"}, but I always get redirected to something like https://web.example.com/#access_token=*****. I had a similar issue with Flutter, and that was because I had not added the additional redirect in Supabase but I already did that. I also confirmed that I have CFBundleURLSchemes set in the info.plist for iOS but that did not fix it.
IF SELF-HOSTING:
Check that you do not have spaces after commas in ADDITIONAL_REDIRECT_URLS.
Correct ✅ :
ADDITIONAL_REDIRECT_URLS="URL,URL,URL"
Incorrect ❌ :
ADDITIONAL_REDIRECT_URLS="URL, URL, URL"

(XMLHttpRequest error) Problem with serverside CORS policy

I created a flutter project with a web version and we already have a server for database access that another android/ios app uses. However the web version of the new app is running into problems with cors policy. I've been trying to solve this looking at other stock overflow questions and searching on google without success and was hoping someone can help me figure out what I might be doing wrong.
I've tested making the uri client side both with:
String url = "https://" + host + ":" + port;
Uri uri = Uri.parse(url + "/test");
and
String url = host + ":" + port;
Uri uri = Uri.https(url, "/test");
I then call the server using the http/http package:
Response response = await get(uri).timeout(const Duration(seconds: 17));
As for the structure of the server side code:
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const https = require('https');
const routerOne = require('./path/to/router/file');
const routerTwo = require('./path/to/router/file');
const dotenv = require('dotenv');
const fs = require("fs");
dotenv.config();
console.log('port' + process.env.PORT);
var key = fs.readFileSync('./certs/key.key');
var cert = fs.readFileSync('./certs/cert.crt');
var options = {
key: key,
cert: cert
};
const cors = require('cors');
const app = express();
app.use(cors());
try {
let server = https.createServer(options, app);
server.listen(process.env.PORT, () => {
console.log('Started https server on port ' + process.env.PORT);
});
} catch (err) {
console.log(err);
}
app.get('/test', cors(), function (req, res, next) {
res.json({msg: "This is CORS-enabled for all origins!"})
})
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({limit: '50mb', extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/router/one', routerOne);
app.use('/router/two', routerTwo);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
console.log(err);
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
Unlike android when running web version(Chrome or Edge), I have been unable to get the response from the newly added '/test' on the server side. I'm hoping for some suggestion for how I can get the cors policy to work.
Client side I've tried using Uri.https instead of Uri.parse and I added headers as well.
On the server I tried to follow instructions on how to add cors policy to node.js/express.
Error message from flutter:
Error: XMLHttpRequest error.
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 963:28 get current
packages/http/src/browser_client.dart 69:22 <fn>
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1685:54 runUnary
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 147:18 handleValue
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 766:44 handleValueCallback
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 795:13 _propagateToListeners
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 557:7 [_complete]
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/stream_pipe.dart 61:11 _cancelAndValue
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/stream.dart 1530:7 <fn>
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 334:14 _checkAndCall
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 339:39 dcall
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/html/dart2js/html_dart2js.dart 37309:58 <fn>
at Object.createErrorWithStack (http://localhost:59072/dart_sdk.js:5093:12)
at Error._throw (http://localhost:59072/dart_sdk.js:20399:18)
at Error.throwWithStackTrace (http://localhost:59072/dart_sdk.js:20396:18)
at async._AsyncCallbackEntry.new.callback (http://localhost:59072/dart_sdk.js:40921:18)
at Object._microtaskLoop (http://localhost:59072/dart_sdk.js:40778:13)
at _startMicrotaskLoop (http://localhost:59072/dart_sdk.js:40784:13)
at http://localhost:59072/dart_sdk.js:36261:9
Image of browser: image of browser with network tab
Update Solution
The answer from Ber is correct. This is a problem with certificate. Self signed certificate was being used on our server and by getting a new certificate using Let's encrypt the problem got solved. If anyone else runs into the "XMLHttpRequest error" they may also want to check out the error output in the browser as the "net::ERR_CERT_AUTHORITY_INVALID" was not shown in flutter.
The error code in your screen shot is net::ERR_CERT_AUTHORITY_INVALID
meaning the server's SSL certificate is expired, invalid for the domain or not accepted by the root certificates in your app.

POST request doesn't work on iOS devices in IONIC app

I tried to make post-request to my server from iOS device (iOS emulator inside Xcode). I'm using ionic 5 and VueJS and #capacitor-community/http.
So my code looks like:
methods: {
async submitForm(){
const form_data = this.$store.getters.my_data;
const options = {
url: 'https://my_domain.com/api/page.php',
headers: {"Content-Type": "application/json"},
data: form_data,
};
await Http.post(options)
.then(res => {
if (res.status === 200) {
console.log(res.data)
}
})
.catch((err) => {
console.log(err)
});
}
I have no submit buttons and I'm not using prevent in the method
When I run my project in the web to testing - I have no problems. GET and POST requests works fine (when testing as web-app I have to remove headers: {"Content-Type": "application/json"} for prevent CORS problems).
So, next I run:
ionic build
npx cap copy
Then I try android emulator (inside android-studio). And my app also works great (all types of requests). Builded android app works perfect on real devices too.
But when it comes to iOS... GET request works fine, as expected. But when I press button which initialize POST request - nothing happens! No errors... No alerts... No logs... Just nothing. My backend doesn't get any request. I have no idea what to do.
There are lines in my Info.plist:
<key>WKAppBoundDomains</key>
<array>
<string>www.my_domain.com</string>
<string>https://my_domain.com</string>
</array>
TransportSecurity flag set as TRUE:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
I tried use native fetch, but the result is same - nothing happens.
So I think it is kind of problems with iOS, but I haven't enough knowledges to understand what the problem is.
So, a few days I tried to realize what's wrong with my code.
Finally I found some logs which says:
Unhandled Promise Rejection: DataCloneError: The object can not be cloned.
It means that something wrong with my data I trying to send.
And the reason is:
const form_data = this.$store.getters.my_data;
This line returns not a json object but some Proxy object. The behavior is pretty similar to json: you can use form_data.name or any other values, but swift for some reasons can't use this object.
So, we need just to create new json object for using in post body:
async submitForm(){
const form_data = this.$store.getters.my_data;
const body_data = {};
for (const [key, val] of Object.entries(form_data)) {
body_data[key] = val;
}
const options = {
url: 'https://my_domain.com/api/page.php',
headers: {"Content-Type": "application/json"},
data: body_data,
};
await Http.post(options)
.then(res => {
if (res.status === 200) {
console.log(res.data)
}
})
.catch((err) => {
console.log(err)
});
}
And this code works fine
P.S. be sure that all you values in body_data are standard JS types
I had the same Issue:
Worked in Android and Browser but not on IOS.
VueJS Composition API Uses Some Poxy on Reactive Variables.
Convert it into a JSON Object first - Then it works for me.
const bodyJson = JSON.stringify(bodyParameters);
const options = {
url: `https://my_domain.com/api/page.php`,
headers: { "Content-Type": "application/json" },
data: bodyJson,
};

Ionic 5 - API request working on browser, not on emulated IOS

I have this Ionic 5/Capacitor app, which I'm making an API call to a local server from, that server running on docker at localhost:3000. When I test from the browser, the request is made fine. From Postman it requests fine, too. In my XCode logs the emulator, I see this
[error] - ERROR {"headers":{"normalizedNames":{},"lazyUpdate":null,"headers":{}},"status":0,"statusText":"Unknown Error","url":"http://localhost:3000/pins","ok":false,"name":"HttpErrorResponse","message":"Http failure response for http://localhost:3000/pins: 0 Unknown Error","error":{"isTrusted":true}}
The really interesting part, is that I'm running Fiddler to monitor the request as it's made. Fiddler gets a 200 as well, I can even see the response data. So, Fiddler sees the proper network call, but then my Ionic app gets that error. That makes me feel like it's an Ionic/Emulator/IOS problem, but I don't have enough familiarity with Ionic to know right off the bat what it is.
Here's the code responsible for making the request:
ngOnInit() {
const request = this.http.get('http://localhost:3000/pins');
this.refresh$.subscribe(
(lastPos: { latitude?: any; longitude?: number }) => {
request.subscribe(data => {
if (data) {
this.addMarkersToMap(data, lastPos);
}
});
}
);
}
And the HTTPClient imported in the constructor is from Angular:
import { HttpClient } from '#angular/common/http';
I ended up having to use this package, doing a check on if I'm on mobile or not.
https://ionicframework.com/docs/native/http/
Try with this :
const request = this.http.get('http://localhost:3000/pins', { observe: 'response', withCredentials: true });
Solution 2 : capacitor.config.json
"server": {
"hostname": "localhost", (maybe try precising the port number too)
}
Solution 3 : On your Express server (from https://ionicframework.com/docs/troubleshooting/cors)
const express = require('express');
const cors = require('cors');
const app = express();
const allowedOrigins = [
'capacitor://localhost',
'ionic://localhost',
'http://localhost',
'http://localhost:8080',
'http://localhost:8100'
];
// Reflect the origin if it's in the allowed list or not defined (cURL, Postman, etc.)
const corsOptions = {
origin: (origin, callback) => {
if (allowedOrigins.includes(origin) || !origin) {
callback(null, true);
} else {
callback(new Error('Origin not allowed by CORS'));
}
}
}
// Enable preflight requests for all routes
app.options('*', cors(corsOptions));
app.get('/', cors(corsOptions), (req, res, next) => {
res.json({ message: 'This route is CORS-enabled for an allowed origin.' });
})
app.listen(3000, () => {
console.log('CORS-enabled web server listening on port 3000');
});

Fetch not working on react native when run on Expo from iphone

So it's actually been on and off the past few days, the fetch function for POST method (for login purposes) on my app would suddenly stop working when I'm not even making any changes to the code.
I spent hrs tracking down the bug the first time this happened but realized that the code is still running fine on Android simulator that I run from Android studio.
This problem only happens on my iphone device when I run the code via expo.
is there any sort of convention on how to tackle this issue?
I've been googling for a few days now but no one forum actually agreed on a solution, some works but says it's unstable and some just doesn't work.
I'm pretty new to expo, react native, and everything in general, so please enlighten me using "english" lol
EDIT: since I was asked about the code, here it is, I hope it helps:
export function login(user, callback){
var endpoint = "oauth/token";
const { username, password } = user;
//from https://scotch.io/tutorials/how-to-encode-and-decode-strings-with-base64-in-javascript
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9+/=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}};
let header = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": ("Basic " + Base64.encode(username+":"+password))
};
let userData = {
"grant_type": "password",
"username": username,
"password": password
};
return fetchAPI(endpoint,'POST', header, userData)
.then((tokenJson) => {
alert("\nAccess Token:\n\n" + tokenJson.access_token + "");
callback(true, {exists : true, token : tokenJson.access_token}, null);
})
.catch((error) => {
alert(error);
callback(false, null, error);
});
}
And here's the fetchAPI function (a generic fetch function) called from that function:
export function fetchAPI(endpoint, method, header, data) {
let url = 'http://10.64.2.149:8081/' + endpoint;
let options = {
method: method,
headers: header,
body: stringify(data) //from qs-stringify package
};
return fetch(url, options)
.then(response => {
return response.json()
.then((json) => { ...//not relevant from this point on
The fetch 'POST' seems to always get stuck at response.json(), it just never resolves until it returns "network request failed". But as I said only happens sometimes when I run it on iphone via expo. It is fine on Android sim.
Thanks! :)

Resources