flutter web: how to connect to a rest API or localhost - rest

My code:
void checkState() async {
print("CTC");
var url = "http://localhost:3000";
try {
var respX = await http.get(url);
} catch (err) {
print("response Arrived: $err");
}
}
But it is not possible:
https://github.com/flutter/flutter/issues/43015#issuecomment-543835637
I am using google chrome for debugging. simply pasting http://localhost:3000 allows me to connect to the URL from the same browser.
Is there any way to do it?

This issue was not with the flutter. It is the CORS policies in the browser as well as the server that blocked the request. I hosted it in a nodejs server with express. Here what I have did to solve this:
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
You can change the 'Access-Control-Allow-Origin' to the domain you are calling from if you want to. Else it will allow request from everywhere.

Remember, the localhost of your emulator is not the localhost of your machine. To test the API running on your machine you have to point to the ip adress of your computer

Related

How to connect my app to SocketIO server if i have CORS enabled

I'm trying to connect my Flutter APP to my SocketIO server (v2), if I enable cors
const io = require("socket.io")(httpServer, {
origins: ["http://localhost:5500", "*", "*:*"]
})
It shows this error (on Android Studio)
I/flutter (20998): reconnect_error: WebSocketException: Connection to 'http://192.168.1.8:3000/socket.io/?EIO=3&transport=websocket#' was not upgraded to websocket
If I disable cors it works perfectly, but I need cors because I need to be able to connect my test file (chat.html) that runs on localhost:5500, and in the future, connect my Flutter Web App
const io = require("socket.io")(httpServer, {
allowRequest: (req, callback) => {
const origin = req.headers.origin
const origins = [
undefined,
"http://localhost:5500",
"http://127.0.0.1:5500"
]
callback(null, origins.includes(origin))
}
})
(This works only for v2)

GET request to port 81 using axios (or even js native fetch)

I have a Node.js API running on port 81, and want to hit the endpoint from JavaScript like this:
function fetchFromApi() {
const axios = require('axios');
console.log('using port 81',axios.defaults);
axios.request({
method: 'get',
url:'/api/getAccountList',
port: 81, // port options is not valid - this does not have the desired result
})
.then( response => {
console.log(response);
const data = response.data;
const errors = (data.errors) ? data.errors : false;
if (errors) {
setErrors(errors);
}
})
.catch( reason => {
console.log(reason);
});
}
The network tab in chrome developer tools show this request still went to port 80.
When I try to code the entire protocol, port, host and url in the axios request, I get a CORS error:
axios.get('http://localhost:81/api/getAccountList')
Error is:
Access to XMLHttpRequest at 'http://localhost:81/api/getAccountList'
from origin 'http://localhost' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
My API server is a simple Node.js server:
const express = require('express');
const app = express();
const port = 81;
app.get('/api/getAccountList', (req, res) => {
const userIdBy = req.params.userIdBy;
const apiToken = req.params.apiToken;
if (!(userIdBy && apiToken)) {
res.status(200).json({errors:['Missing credentials']});
return true;
}
// check the user id and api token match up:
console.log('Hello');
});
app.listen(port);
How can I make my client query the API using HTTP on port 81?
CORS is a security feature in most browsers that disables cross-origin requests—i.e., requests from a different hostname. To surpass it, install the cors dependency on your Express server via npm using:
npm install cors
Then you need to add it to every app via the cors() function to every {{httpMethod}} you want to allow other domains to make requests to.
Try editing your code like this:
const express = require('express');
const cors = require('cors')
const app = express();
const port = 81;
app.get('/api/getAccountList', cors(), (req, res)=>{})
On the client side, to get Axios to GET from port 81 on the same host as the javascript is running I used:
import axios from 'axios';
//...
//...
axios.defaults.baseURL = window.location.protocol + "//" + window.location.hostname + ":81";
const result = await axios('/your/endpoint');
//...
//...
Can you try to add this to your Node.js server?
// Add headers
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:81');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
You can try to add only Access-Control-Allow-Origin header or modify others to your needs.
To achieve the required CORS protection AND avoid hard coding the servers FQDN / hostname, I used this code in my node api server:
const express = require('express');
const app = express();
const apiProviderPort = 81;
const allowedApiConsumerPort = 80;
app.use(function (req, res, next) {
const host = req.get('host'); // NOTE host is the fqdn:port
const hostSplit = host.split(':');
var fqdn;
if (hostSplit.length == 1) {
// I am not sure this is needed, it will be if hostname is fqdn[:port]
fqdn = host;
} else if (hostSplit.length == 2) {
fqdn = hostSplit[0];
} else {
console.log('Error the host contained multiple colons!');
}
console.log('protocol:',req.protocol,'host:',host,'fqdn:' + fqdn);
// next line edited March 2020 - I changed + '//' + to + '//:' +
// as the developer tools console showed
// The 'Access-Control-Allow-Origin' header contains the invalid value 'http//localhost:3000'.
const allowableOrigin = req.protocol + '//' + fqdn + ':' + allowedApiConsumerPort;
console.log('allowableOrigin:',allowableOrigin)
res.setHeader('Access-Control-Allow-Origin', allowableOrigin);
next();
});
app.get('/api/userDocReportData/', (req, res) => {
const userIdBy = req.params.userIdBy;
const apiToken = req.params.apiToken;
if (!(userIdBy && apiToken)) {
res.status(200).json({errors:['Missing credentials']});
return true;
}
// check the user id and api token match up:
// ...
// get your payload etc
res.status(200).json({errors:false,payload:{} });
});
app.listen(apiProviderPort);
I enhanced #webprogrammers answer above as I wanted code that could work in any environment (localhost; test.example.com, live.example.com etc)

I'm getting a Web Push Error Code Status 403, which is driving me nuts, because its telling me to use firebase. What's going on?

I keep getting a WebPush Error (Status Code 403) fro Chrome for a PWA I'm building and the body says that I need to use the VAPID server key from the 'firebase console' but I used nodes Web-Push library to generate the VAPID Keys, whats going on? Do I have to use firebase to build PWAs in Chrome?
Here's the Error Message I'm getting from the browser when I send a push notification:
name: 'WebPushError',
message: 'Received unexpected response code',
statusCode: 403,
headers:
{ 'content-type': 'text/plain; charset=utf-8',
'x-content-type-options': 'nosniff',
'x-frame-options': 'SAMEORIGIN',
'x-xss-protection': '0',
date: 'Thu, 31 Oct 2019 19:59:02 GMT',
'content-length': '194',
'alt-svc':
'quic=":443"; ma=2592000; v="46,43",h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000',
connection: 'close' },
body:
'the key in the authorization header does not correspond to the sender ID used to subscribe this user. Please ensure
you are using the correct sender ID and server Key from the Firebase console.\n',
endpoint:
'https://fcm.googleapis.com/fcm/send/exXmW3OFOTY:APA91bEKW_vxnvOZohog34pprDH6XvBsxtfnUpBdYY7z_7q4GZGa4wrmtBBg4kTRwLtgy3lNpCs8SMlvOr4nY-Fu_4zUus6zEJh69581Ier14QZxkEEVXyZHKRaZcmHa3zmbZRB4VD7Z
and here's the code that is running my node server:
//Handle imports
const express = require('express')
const cors = require('cors')
const bodyParser = require('body-parser')
const webPush = require('web-push')
const vapidKeys = require('./vapid.json')
const path = require('path')
//Setup application
const app = express()
app.use(cors())
app.use(bodyParser.json())
app.use('/static', express.static(path.join(__dirname,'frontend')))
const port = 8080
//Set up webpush
webPush.setVapidDetails(
'mailto: <email>',
vapidKeys.publicKey,
vapidKeys.privateKey
)
const pushOptions = {
proxy: '<proxy>'
}
//setup Push Notification
const sendNotification = (subscription, dataToSend='') => {
webPush.sendNotification(subscription, dataToSend, pushOptions).catch(error => { console.log('Damn it: ', error.message, '||', error)
})
}
//Server Routes Defined
app.get('/', (req, res) => res.sendFile('index.html', { root: './' }))
//Setup Database Methods
const dummyDb = {subscription: null}
const saveToDatabase = async subscription => {
dummyDb.subscription = subscription
}
//Other Server Routes
app.post('/save-subscription', async (req, res) => {
const subscription = req.body
await saveToDatabase(subscription)
console.log('subscribed!')
res.json({message: 'success'})
})
app.get('/send-notification', (req, res) => {
const subscription = dummyDb.subscription
const message = 'hello world'
sendNotification(subscription, message)
res.json({message: dummyDb.subscription})
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
I have node.js express, postgres, angular 8 app.
I had the same problem and I got it working by adding the "gcm_sender_id": in the manifest.webmanifest file (or manifest.json I also used firebase generated public and private keys.
your gcm_sender_id is your project id in google cloud or firebase sender id
Same situation and almost lost my sanity. I tried inserting gcm_sender_id with a Firebase senderId and worked finally. I didn't have a Firebase account, but I was able to create a project in seconds and my senderId was ready to be used in the messaging settings.
But a caveat: After my modification in the manifest.json (in my case) in the root's folder, it was needed to uninstall the current service worker and restart my React project. Then I followed again all steps back by asking permissions and subscribe the user and finally trigger a push notification.
During my heat researches for a solution, I found that gcm_sender_id is also used to send and validate push messages from other browsers. According to Google Web Updates:
For Chrome prior to version 52, Opera Android and the Samsung Browser,
you're also still required to include a 'gcm_sender_id' in your web
app's manifest.json. The API key and sender ID are used to check
whether the server making the requests is actually allowed to send
messages to the receiving user.

Connecting Vue to Express - 404 Not Found

I'm creating a simple app to practice connecting Vue to an Express server. I have a form that I'm attempting to send to the back end, but I can't seem to get my data to the back-end.
The error I'm receiving is:
POST http://localhost:8080/login 404 (Not Found)
My best guess is that the method in my Vue can't find a matching route on my server? If so, I'm confused as I have a route for login.
In my Vue script:
const axios = require('axios');
export default {
data: function() {
return {
user: {
email: '',
password: ''
}
}
},
methods: {
sub() {
var user = {
email: this.user.email,
password: this.user.password
}
axios.post('/login', user)
.then(res => console.log(res))
.catch(err => console.log(err))
}
}
}
On by back-end:
const path = require('path');
const express = require('express');
const app = express();
app.use(express.static(path.join(__dirname, '..')));
app.post('/login', function(req, res) {
console.log("Server HIT!!!!!!!!!!!!!!!!!!!!")
})
app.get('*', function (req, res) {
return res.sendFile('../index.html');
});
app.listen(3000);
console.log('Express server listening on port 3000');
Express is running on another port than your vue application. Vue is standard http which is 8080, but express runs on 3000 with this line:
app.listen(3000);
You are sending the request to /login, which from the point of view of your frontend is http://localhost:8080, but that's not where express is available.
Basically all you have to do is send the request to http://localhost:3000/login, simple as that.
By default express do not allow cross origin request i.e CORS. You have to enable it by setting middleware. add below lines in you server file and must be before declaring any routes
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});

MongoJS, Node, MongoLab - How to get the database online

I have created an hybrid application with Ionic, MongoJS, Angular JS (Mean Stack).
My application worked fine, locally. This means my mongod (Mongo Service) and my mongo ran locally on my pc. I also have a server.js (node) which is located locally.
Now I would like to use MongoLab (MongoDB as a Service) to change the location of my database from local to online.
I intented to change just the connection path, but for some reason I receive an undefined through my http get request.
My code:
server.js
var express = require('express');
var app = express();
var mongojs = require('mongojs');
//var db = mongojs('nzbaienfurtdb', ['nzbaienfurtdb']); // This is my old mongojs which ran locally and worked fine.
var databaseUrl = 'mongodb://dbuser:password#ds045604.mongolab.com:45604/nzbaienfurtdb';
var db = mongojs(databaseUrl, ['nzbaienfurtdb']); // database online with MongoLab
var bodyParser = require('body-parser');
app.use(express.static(__dirname + "/www"));
app.use(bodyParser.json());
app.get('/nzbaienfurtdb', function (req, res) {
console.log("I received a GET request")
db.nzbaienfurtdb.find(function (err, docs){
console.log(docs);
res.json(docs);
});
});
app.listen(3000);
console.log("server running on 3000");
This is a part of my get request out of a service:
service.js
return {
getUsers: function(){""
$http.get("/nzbaienfurtdb")
.success(function(data, status, headers, config){
headers("Cache-Control", "no-cache, no-store, must-revalidate");
headers("Pragma", "no-cache");
headers("Expires", 0);
users = angular.fromJson(data);
})
.error(function(data, status, headers, config){
console.log('Data could not be loaded, try again later');
})
return users;
}
MongoLab has been setup already.
My questions:
Why do I get an undefined for my http GET Request?
What happens with my server.js file when I want to deploy the Ionic App on for example an Android Phone? Is the server running on the device?
Since I have changed the var db variable i get also the following error message in my chrome console:
--------- ERROR CODE:
SyntaxError: Unexpected end of input
at Object.parse (native)
at Object.fromJson (http://localhost:3000/lib/ionic/js/ionic.bundle.js:8764:14)
at http://localhost:3000/js/userServices.js:23:27
at http://localhost:3000/lib/ionic/js/ionic.bundle.js:15737:11
at wrappedCallback (http://localhost:3000/lib/ionic/js/ionic.bundle.js:19197:81)
at wrappedCallback (http://localhost:3000/lib/ionic/js/ionic.bundle.js:19197:81)
at http://localhost:3000/lib/ionic/js/ionic.bundle.js:19283:26
at Scope.$eval (http://localhost:3000/lib/ionic/js/ionic.bundle.js:20326:28)
at Scope.$digest (http://localhost:3000/lib/ionic/js/ionic.bundle.js:20138:31)
at Scope.$apply (http://localhost:3000/lib/ionic/js/ionic.bundle.js:20430:24)
I hope somebody can help me out, I am fighting now for ages!
Thank you in advance, guys!
This issue has been resolved after ages!
I had to enable the API on the website of mongolab in my configuration.