Ionic 5 - API request working on browser, not on emulated IOS - 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');
});

Related

Enabling Google Cloud Run chunked encoding

I have tried returning 'transfer-encoding:chunked' header to a large download but the response terminated at "31.9M" which is very close to the documented "32MB" limit.
The Unofficial FAQ states chunked encoding is now possible, but I can't seem to get it working.
Do I have to flip any flags (e.g. https/2) to enable streaming? Is it only possible in some regions? (I am using europe-west1)
The following minimal case does actually stream 45MB over Cloud Run, without any special configuration, confirmed in us-central1 and europe-west1
FROM node:14-slim
COPY index.js index.js
CMD [ "node", "index.js" ]
const http = require('http');
http.createServer((request, response) => {
response.setHeader('Transfer-Encoding', 'chunked');
// 45MB
var i = 1000000;
function nextChunk() {
return new Promise(resolve => {
if (i-- > 0) {
response.write(
'123456781234567812345678123456781234567812345678',
() => nextChunk()
);
} else {
response.end();
}
})
};
Promise.all(nextChunk())
}).listen(process.env.PORT || 8080);
Even after straming into chunks I'm always getting error after 32 MB reponse size, I can't get the response header 'Transfer-Encoding' = 'chunked' from Cloud Run service response :
I'm using NestJs, and I can get it in the response Headers when I execute the app locally.
I'm specifying it as :
#Get('streamable')
#Header('Transfer-Encoding', 'chunked')
async streamable(#Res() res) { etc.. res.write(chunk)}

Is there any way to track an event using firebase in electron + react

I want to ask about how to send an event using firebase & electron.js. A friend of mine has a problem when using firebase analytics and electron that it seems the electron doesn't send any event to the debugger console. When I see the network it seems the function doesn't send anything but the text successfully go in console. can someone help me to figure it? any workaround way will do, since he said he try to implement the solution in this topic
firebase-analytics-log-event-not-working-in-production-build-of-electron
electron-google-analytics
this is the error I got when Try to use A solution in Point 2
For information, my friend used this for the boiler plate electron-react-boilerplate
The solution above still failed. Can someone help me to solve this?
EDIT 1:
As you can see in the image above, the first image is my friend's code when you run it, it will give a very basic example like in the image 2 with a button to send an event.
ah just for information He used this firebase package :
https://www.npmjs.com/package/firebase
You can intercept HTTP protocol and handle your static content though the provided methods, it would allow you to use http:// protocol for the content URLs. What should make Firebase Analytics work as provided in the first question.
References
Protocol interception documentation.
Example
This is an example of how you can serve local app as loaded by HTTP protocol and simulate regular browser work to use http protocol with bundled web application. This will allow you to add Firebase Analytics. It supports poorly HTTP data upload, but you can do it on your own depending on the goals.
index.js
const {app, BrowserWindow, protocol} = require('electron')
const http = require('http')
const {createReadStream, promises: fs} = require('fs')
const path = require('path')
const {PassThrough} = require('stream')
const mime = require('mime')
const MY_HOST = 'somehostname.example'
app.whenReady()
.then(async () => {
await protocol.interceptStreamProtocol('http', (request, callback) => {
const url = new URL(request.url)
const {hostname} = url
const isLocal = hostname === MY_HOST
if (isLocal) {
serveLocalSite({...request, url}, callback)
}
else {
serveRegularSite({...request, url}, callback)
}
})
const win = new BrowserWindow()
win.loadURL(`http://${MY_HOST}/index.html`)
})
.catch((error) => {
console.error(error)
app.exit(1)
})
async function serveLocalSite(request, callback) {
try {
const {pathname} = request.url
const filepath = path.join(__dirname, path.resolve('/', pathname))
const stat = await fs.stat(filepath)
if (stat.isFile() !== true) {
throw new Error('Not a file')
}
callback(
createResponse(
200,
{
'content-type': mime.getType(path.extname(pathname)),
'content-length': stat.size,
},
createReadStream(filepath)
)
)
}
catch (err) {
callback(
errorResponse(err)
)
}
}
function serveRegularSite(request, callback) {
try {
console.log(request)
const req = http.request({
url: request.url,
host: request.url.host,
port: request.url.port,
method: request.method,
headers: request.headers,
})
if (req.uploadData) {
req.write(request.uploadData.bytes)
}
req.on('error', (error) => {
callback(
errorResponse(error)
)
})
req.on('response', (res) => {
console.log(res.statusCode, res.headers)
callback(
createResponse(
res.statusCode,
res.headers,
res,
)
)
})
req.end()
}
catch (err) {
callback(
errorResponse(err)
)
}
}
function toStream(body) {
const stream = new PassThrough()
stream.write(body)
stream.end()
return stream
}
function errorResponse(error) {
return createResponse(
500,
{
'content-type': 'text/plain;charset=utf8',
},
error.stack
)
}
function createResponse(statusCode, headers, body) {
if ('content-length' in headers === false) {
headers['content-length'] = Buffer.byteLength(body)
}
return {
statusCode,
headers,
data: typeof body === 'object' ? body : toStream(body),
}
}
MY_HOST is any non-existent host (like something.example) or host that is controlled by admin (in my case it could be electron-app.rumk.in). This host will serve as replacement for localhost.
index.html
<html>
<body>
Hello
</body>
</html>

Unable to establish connection between Node.JS and React-Native (Socket.IO)

I'm new to React and Node and i'm trying to make a simple WebSocket using Socket.IO which gonna simply send greetings to all connected users and the user will respond to the server.
The Node.JS server is running on a Windows PC while the React-Native app is running on both iOS and Android devices.
Node.JS server code is the following
var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
const bodyParser = require('body-parser');
const mysql = require('mysql');
const connection = mysql.createPool({
host : 'localhost',
user : 'root',
password : 'block',
database : 'visualpos'
});
// Creating a GET route that returns data from the 'users' table.
app.get('/prenotazioni', function (req, res) {
// Connecting to the database.
connection.getConnection(function (err, connection) {
// Executing the MySQL query (select all data from the 'users' table).
connection.query("SELECT Data, Importo_Doc FROM tabella_pagamenti", function (error, results, fields) {
// If some error occurs, we throw an error.
if (error) throw error;
// Getting the 'response' from the database and sending it to our route. This is were the data is.
res.send(results)
});
connection.release();
});
});
app.get('/', function(req, res){
res.send('<h1>Hello World</h1>');
});
// Starting our server.
http.listen(3000, () => {
console.log('In ascolto sulla porta *:3000');
});
io.emit('saluta', 'Ciao dal server :)');
io.on('connected', (data) => {
console.log(data);
});
Actually GET part of the code works perfectly but the Socket.IO seems death.
The client doesn't get any response and server the same i think the Socket.IO server simply doesn't start..
In XCode Debug i get the following errors when the app is running on the iPhone
And i even get on both devices warning "Unrecognized WebSocket connection option(s) 'agent', 'perMessageDeflate',..."
And here is the code i'm using in React-Native
import io from 'socket.io-client'
var socket = io('http://192.168.100.50:3000', {
jsonp: false,
transports: ['websocket'],
autoConnect: true,
reconnection: true,
reconnectionDelay: 500,
reconnectionAttempts: Infinity
});
componentDidMount(){
socket.emit('connected','we');
socket.on('saluta',(data) => { alert(data); });
}
On socket.io getStarted section, they use a "connection" event instead of "connected" (https://socket.io/get-started/chat/).
io.on('connection', function(socket){
console.log('a user connected');
socket.on('disconnect', function(){
console.log('user disconnected');
});
});

How do I get webpack-dev-server to accept POST requests

In my project I call:
$ webpack-dev-server --history-api-fallback
And it starts an express server (I'm assuming) available on localhost:8080.
It works great except that I want to submit a form via POST into an iframe loading my app; localhost:8080 in development and something else in production.
I don't expect to do anything with that POST data in development, but in production, it needs to be POST.
When I try to use POST however, it cannot find POST /
Is there a configuration option or some other solution that will allow me to use the webpack-dev-server? (I really don't want to have to write my own server for this).
#cowCrazy had half of the story, but didn't show how to respond with the same response for GET in the case of POST, which is what I was looking for.
In the Webpack config, you do this:
module.exports = {
...,
devServer: {
setup(app) {
app.post('*', (req, res) => {
res.redirect(req.originalUrl);
});
},
}
}
This will just take the POST URL and redirect with the same URL, making it a GET request.
Instead of having a server error, it will redirect with GET.
What you are looking for is devServer. Bellow you can see my config for it. Under setup(app) you can add "almost" whatever you want:
module.exports = {
...,
devServer: {
inline: true,
port: 3000,
publicPath: '/',
setup(app){
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.get("/get/some-data", function(req, res){
console.log(req);
res.send("GET res sent from webpack dev server")
})
app.post("/post/some-data", bodyParser.json(), function(req, res){
console.log(req.body);
res.send("POST res sent from webpack dev server")
})
}
}
}
EDIT:
I have pushed a minimalistic example to github if you wanna take a better look.
Check if it solves your problem by converting the POST request to GET request:
bypass: function (req, res, proxyOptions) {
const url = req.url;
req.method = 'GET';
if (url.indexOf('?') > -1) {
return url.replace('?', '.json?');
} else {
return url + '.json';
}
}

Error while using superagent in react native ios app

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.

Resources