Integrating Backbone with Nodejs - javascript

Trying to fetch Nodejs response from Backbone Model.
Update
Changed Model code as following and getting error
XMLHttpRequest cannot load http://localhost:3000/getDifficulty. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access.
var Bitcoin = Backbone.Model.extend({
url:'http://localhost:3000/getDifficulty'
});
var info = new Bitcoin ();
info.fetch();
Node JS is very straight forward and works fine for the url http://localhost:3000/getDifficulty
Server side Node JS
var http = require('http'),
express = require('express'),
bitcoin = require('bitcoin');
var app = express();
var client = new bitcoin.Client({
host: 'localhost',
port: 8332,
user: 'himanshuy',
pass: 'xxx'
});
app.get('/getDifficulty', function(req, res) {
client.getInfo(function(err, info) {
if(err) {
res.send('Bitcoin error: '+ err);
} else {
res.send('Difficulty: ' + info);
}
});
});
app.listen(3000);
Client Side Backbone Model
var Bitcoin = Backbone.Model.extend({
urlRoot:'http://localhost:3000/getDifficulty'
});
var info = new Bitcoin();
It works fine if give some value to the model like this
var info = new Bitcoin({version:"1.0.0.", balance:"20.03"});
Which means that model is not getting the result from url.
Please help.
Note: I am fairly new to both backbone and Nodejs

Try using
var Bitcoin = Backbone.Model.extend({
url:'getDifficulty'
});
var info = new Bitcoin();
info.fetch();
And take a look at the console to see the response from the server. From the looks of it, the above won't work, because you're not returning a json object res.send('Difficulty: ' + info). Backbone expects JSON data to be provided (and only JSON) so it can load the values into the model instance.
If what you're returning from the server needs to be modified before being loaded into the modekl, you need to implement the parsefunction (see http://backbonejs.org/#Model-parse):
var Bitcoin = Backbone.Model.extend({
url:'getDifficulty',
parse: function(response){
// the return value should be what needs to loaded into the model
// for example, if we need to only have the `data`attribute in the model:
return response.data;
}
});

If you are getting errors like
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'null' is therefore not allowed access.
You may need to configure your browser to disable CORS or web security settings. This Chrome extension should get around that error.
In Firefox, Force CORS extension is helpful.
Launching Chrome with a certain command line argument can also prevent these type of errors, but at the cost of vulns like XSS becoming easier to suffer: On Windows in the target field, this works - with the consequence of lower browser security as well:
"C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-web-security

Related

Fetch problem with node.js express server

I'm having some trouble with the fetch and node.js.
In my frontend when i click a button, i would like to send a post request in order to receive an array from my backend as answer. I'n my backend i'm using node.js with express, in my frontend i'm using the fetch function.
The error that occours is the following:
Access to fetch at 'http://localhost:8080/api' from origin 'real localhost address' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Code Here
const getArray = async() => {
const data = await fetch ("http://localhost:8080/api");
const dataJson = await data.json();
console.log(dataJson)
}
getArray();
In my server i've got
app.post("/api", (req,res) => {
res.sendFile(JSON.stringify(arr));
});
You need to add request options. Please refer to the MDN docs for further information.
As #Kudah said, you should read the docs.
Fetch (and XMLHttpRequest) follow the same-origin policy. This means that browsers restrict cross-origin HTTP requests from within scripts. A cross-origin request occurs when one domain (for example http://example2.com/) requests a resource from a separate domain (for example http://example1.com/).
The easiest way to solve this, (If you don't want to dig too much into this)
const whiteList = [ "https://myRealBackendUrl-1", "https://myRealBackendUrl-2" ];
// you can also pass a string here instead here instead of array
const corsOptions = {
credentials: true,
origin: process.env.NODE_ENV !== production ? "http://localhost:4000" : whiteList
// if you are in a dev environment, you probably want something like localhost
// http://localhost:4000 is just a demo backend. replace it with your own.
// if you are in a production environment, for example heroku then your backend
// url will be something like http://example.herokuapp.com
// in that case `const whiteList = [ "http://example.herokuapp.com" ];`
};
app.use(cors(corsOptions));
The above code should be enough for the normal use case.
There is also callback function, it is if you want to run some function of your own. Don't read it if you dont plan to use any dynamic checking
var corsOptionsDelegate = async (req, callback) => {
var corsOptions = { origin: false };
try {
// you can do some dynamic check here
// For example: check database for some conditions then allow access
if( myDatabaseSays == true ) corsOptions.origin = true;
else corsOptions.origin = false;
} catch (err) {
console.log(err);
// corsOptions.origin = false;
}
callback(null, corsOptions) // chain it
}
Anyway read the docs properly for more info
[1]: https://expressjs.com/en/resources/middleware/cors.html

Unable to establish Handshake with Public Websocket API for Kraken

I'm trying to make a watchlist for cryptocurrency tickers You type a ticker, add it, and it will show you real time prices in a table format.
My first step is to try and establish a handshake connection with the Kraken websocket API (documentation here: https://www.kraken.com/features/websocket-api#connectionDetails)
My ask:
At the moment, all I want to do is be able to console log a "connection success" for when I'm connected with the websocket API from Kraken (crypto exchange). I'm trying to do this via the portion below (scroll all the way down to see all of the code)
socket.onopen = function(event) {
socketStatus.innerHTML = 'Connected to: ' + event.currentTarget.url;
socketStatus.className = 'open';
};
I've got an index.html file, and an app.js file. When I open the index.html file in chrome, I get an error:
app.js:5 WebSocket connection to 'ws://ws-sandbox.kraken.com/' failed: Error during WebSocket handshake: Unexpected response code: 521
I've tried with only this line of code for websocket related stuff
var socket = new WebSocket('ws://ws-sandbox.kraken.com')
I've also tried to use the get method, provided in examples from here
https://medium.freecodecamp.org/here-is-the-most-popular-ways-to-make-an-http-request-in-javascript-954ce8c95aaa
$.get('ws://ws-sandbox.kraken.com',function(data){console.log(`${data}`)})
in my app.js file, my question is, apart from line below what else do I need to successfully do the handshake? Do I need to send a GET request with header information (please see very end)?
var socket = new WebSocket('ws://ws-sandbox.kraken.com')
in the documentation, you'll see connection details. Connection details for sandbox environment. The URL is ws-sandbox.kraken.com
link: https://www.kraken.com/features/websocket-api#connectionDetails
I've followed the example here:
https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
GET REQUEST QUESTION:
I was looking at this site as an example:
https://blog.teamtreehouse.com/an-introduction-to-websockets
and it said I need to send an HTTP request to the server using something similar to this. I'm just not sure if this is required for what I'm trying to do.
GET ws://websocket.example.com/ HTTP/1.1
Origin: http://example.com
Connection: Upgrade
Host: websocket.example.com
Upgrade: websocket
CODE IN APP.JS FILE
$(document).ready(function(){ console.log('page ready')
var socket = new WebSocket('ws://ws-sandbox.kraken.com')
$.get('ws://ws-sandbox.kraken.com',function(data){console.log(`${data}`)})
var form = document.getElementById('message-form');
var messageField = document.getElementById('message');
var messagesList = document.getElementById('messages');
var socketStatus = document.getElementById('status');
var closeBtn = document.getElementById('close');
socket.onopen = function(event) { //LOGGING SUCCESSFUL CONNECTION HERE
socketStatus.innerHTML = 'Connected to: ' + event.currentTarget.url;
socketStatus.className = 'open';
};
})
I know this is an old question but I was having the same issue and wanted to provide my solution in case anyone else comes here in need of it.
So the reason I found for this error was because I using a protocol that was not supported by the API. I was using TLS 1.0 where the Kraken API only supports 1.2/1.3:
https://support.kraken.com/hc/en-us/articles/360023264371-TLS-upgrade-that-might-affect-your-API-connections
So to solve it, I simply set my websocket client to use TLS 1.2 as the protocol.
From a browser, using the Websocket() built-in api:
new WebSocket("wss://ws.kraken.com").onopen = function(){
this.onclose = () => console.log("SOCKET CLOSED")
this.onmessage = (e) => console.log(JSON.parse(e.data))
this.send(JSON.stringify({
"event": "subscribe",
"pair": ["XBT/USD"],
"subscription": {
"interval": 1,
"name": "ohlc"
}
}), (e) => console.log(e))
}

Customize cors-anywhere

I have deployed (hosted) cors-anywhere in Heroku, but i don't know how to customize it.
For example, I want to add a site link in whitelist.
I get data from this link: http://fmon.asti.dost.gov.ph/dataloc.php?param=rv&dfrm=null&dto=null&numloc=1&data24=1&locs[]=711
How will I do it? I have tried touching the server.js file:
// Listen on a specific host via the HOST environment variable
var host = process.env.HOST || '0.0.0.0';
// Listen on a specific port via the PORT environment variable
//var port = process.env.PORT || 443;
var port = process.env.PORT || 8080;
// Grab the blacklist from the command-line so that we can update the blacklist without deploying
// again. CORS Anywhere is open by design, and this blacklist is not used, except for countering
// immediate abuse (e.g. denial of service). If you want to block all origins except for some,
// use originWhitelist instead.
var originBlacklist = parseEnvList(process.env.CORSANYWHERE_BLACKLIST);
//var originWhitelist = ['http://fmon.asti.dost.gov.ph/dataloc.php','https://fmon.asti.dost.gov.ph/dataloc.php','http://fmon.asti.dost.gov.ph','https://fmon.asti.dost.gov.ph'];
var originWhitelist = parseEnvList(process.env.CORSANYWHERE_WHITELIST);
function parseEnvList(env) {
if (!env) {
return [];
}
return env.split(',');
}
// Set up rate-limiting to avoid abuse of the public CORS Anywhere server.
var checkRateLimit = require('./lib/rate-limit')(process.env.CORSANYWHERE_RATELIMIT);
var cors_proxy = require('./lib/cors-anywhere');
cors_proxy.createServer({
originBlacklist: originBlacklist,
originWhitelist: originWhitelist,
requireHeader: ['origin', 'x-requested-with'],
checkRateLimit: checkRateLimit,
removeHeaders: [
'cookie',
'cookie2',
// Strip Heroku-specific headers
'x-heroku-queue-wait-time',
'x-heroku-queue-depth',
'x-heroku-dynos-in-use',
'x-request-start',
],
redirectSameOrigin: true,
httpProxyOptions: {
// Do not add X-Forwarded-For, etc. headers, because Heroku already adds it.
xfwd: false,
},
}).listen(port, host, function() {
console.log('Running CORS Anywhere on ' + host + ':' + port);
});
but when I access the data and look at the console log, it returns a 403 error which is forbidden.
NOTE: When you say self hosted CORS it will only work for your site to
proxy. CORS setting on your server is for you not for the list of
sites you mentioned. They will be having their own CORS filters setup.
403 actually refers to the forbidden resource rather than a CORS Issue. Cors issue will look something like as follows:-
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'yourUrl' is therefore not allowed access. The response had HTTP status code 400
For cors-anywhere the whitelisting code is pretty simple as mentioned below:-
// Listen on a specific host via the HOST environment variable
var host = process.env.HOST || '0.0.0.0';
// Listen on a specific port via the PORT environment variable
var port = process.env.PORT || 8080;
var cors_proxy = require('cors-anywhere');
cors_proxy.createServer({
originWhitelist: ['http://fmon.asti.dost.gov.ph'], // Allow all origins
requireHeader: ['origin', 'x-requested-with'],
removeHeaders: ['cookie', 'cookie2']
}).listen(port, host, function() {
console.log('Running CORS Anywhere on ' + host + ':' + port);
});
This should Ideally work for you with your application calling this somewhere.
If you are getting 403 while accessing this URL from your application
then be sure the URL you mentioned is protected and you must get
proper authentication done before requesting it.
I spent 3 days looking for the cause, got a 403 error for some sites and realized that the problem may be that they can not accept requests from "origin" different from theirs.
I just tried removing those headers on the proxy server and everything worked!
removeHeaders: ['origin', 'referer']

Need to acces Client IP not the server IP for a weather API

I want to create a server-side app using node.js with express. At the moment I am able to get the json document with the location and temperature but after I used pykite to get it online the application would only get the server location to the one who is accessing it. Here is the code in its current form:
var express = require('express');
var app = express();
var request = require('request');
app.get('/api/weather/current_temperature', function (req, res) {
request('http://api.wunderground.com/api/ebb3e0cf5059cce8/conditions/q/autoip.json', function(error, response, body){
if (!error && response.statusCode==200){
res.setHeader('Content-Type', 'aplication/json');
var result = JSON.parse(body);
res.json({ "location": result.current_observation.observation_location.city,"temperature": result.current_observation.temp_c });
}else{
console.log(error, response.statusCode, body);
}
res.end("")
});
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('The app is up.');
});
I admit I'm new to this but I wanna learn. I would like some help implementing it in this code, if it's possible, a way to access the user's location and determine the weather at his/her location.
Thank you in advance.
P.S.: I would also like some links into some documentation, don't wanna skip anything.
The URL you are linking to http://api.wunderground.com/api/YOUR_KEY/conditions/q/autoip.json (which doesn't work because you didn't provide your key) has autoip in the name.
That implies that it will return a result from whatever IP address the request came from.
So you have two options:
Don't make the request from NodeJS. Make the request from the browser. (This probably isn't advisable given the use of an API key and might run into Same Origin Policy issues).
Find a different API (possibly one from the same site) that lets you specify what IP address or location to use.

Angular Cross-Origin Request CORS failure, but node http.get() returns successfully

I am trying to access an API using AngularJS. I have checked the API functionality with the following node code. This rules out that the fault lies with
var http = require("http");
url = 'http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10';
var request = http.get(url, function (response) {
var buffer = ""
response.on("data", function (chunk) {
buffer += chunk;
});
response.on("end", function (err) {
console.log(buffer);
console.log("\n");
});
});
I run my angular app with node http-server, with the following arguments
"start": "http-server --cors -a localhost -p 8000 -c-1"
And my angular controller looks as follows
app.controller('Request', function($scope, $http){
// functional URL = http://www.w3schools.com/website/Customers_JSON.php
$scope.test = "functional";
$scope.get = function(){
$http.get('http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10',{
params: {
headers: {
//'Access-Control-Allow-Origin': '*'
'Access-Control-Request-Headers' : 'access-control-allow-origin'
}
}
})
.success(function(result) {
console.log("Success", result);
$scope.result = result;
}).error(function() {
console.log("error");
});
// the above is sending a GET request rather than an OPTIONS request
};
});
The controller can parse the w3schools URL, but it consistently returns the CORS error when passed the asterank URL.
My app avails of other remedies suggested for CORS on this site (below).
Inspecting the GET requests through Firefox shows that the headers are not being added to the GET request. But beyond that I do not know how to remedy this. Help appreciated for someone learning their way through Angular.
I have tried using $http.jsonp(). The GET request executes successfully (over the network) but the angular method returns the .error() function.
var app = angular.module('sliderDemoApp', ['ngSlider', 'ngResource']);
.config(function($httpProvider) {
//Enable cross domain calls
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
You should understand one simple thing: even though those http modules look somewhat similar, they are totally different beasts in regards to CORS.
Actually, the node.js http.get() has nothing to do with CORS. It's your server that makes a request - in the same way as your browser does when you type this URL in its location bar and command to open it. The user agents are different, yes, but the process in general is the same: a client accesses a page lying on an external server.
Now note the difference with angular's $http.get(): a client opens a page that runs a script, and this script attempts to access a page lying on an external server. In other words, this request runs in the context of another page - lying within its own domain. And unless this domain is allowed by the external server to access it in the client code, it's just not possible - that's the point of CORS, after all.
There are different workarounds: JSONP - which basically means wrapping the response into a function call - is one possible way. But it has the same key point as, well, the other workarounds - it's the external server that should allow this form of communication. Otherwise your request for JSONP is just ignored: server sends back a regular JSON, which causes an error when trying to process it as a function call.
The bottom line: unless the external server's willing to cooperate on that matter, you won't be able to use its data in your client-side application - unless you pass this data via your server (which will act like a proxy).
Asterank now allows cross origin requests to their API. You don't need to worry about these workarounds posted above any more. A simple $http.get(http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10')
will work now. No headers required.I emailed them about this issue last week and they responded and configured their server to allow all origin requests.
Exact email response from Asterank : "I just enabled CORS for Asterank (ie Access-Control-Allow-Origin *). Hope this helps!"
I was having a similar issue with CORS yesterday, I worked around it using a form, hopefully this helps.
.config(function($httpProvider){
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
})
.controller('FormCtrl', function ($scope, $http) {
$scope.data = {
q: "test"//,
// z: "xxx"
};
$scope.submitForm = function () {
var filters = $scope.data;
var queryString ='';
for (i in filters){
queryString=queryString + i+"=" + filters[i] + "&";
}
$http.defaults.useXDomain = true;
var getData = {
method: 'GET',
url: 'https://YOUSEARCHDOMAIN/2013-01-01/search?' + queryString,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
};
console.log("posting data....");
$http(getData).success(function(data, status, headers, config) {
console.log(data);
}).error(function(data, status, headers, config) {
});
}
})
<div ng-controller="FormCtrl">
<form ng-submit="submitForm()">
First names: <input type="text" name="form.firstname">
Email Address: <input type="text" ng-model="form.emailaddress">
<button>bmyutton</button>
</form>
</div>
Seems to work with the url you posted above as well..
ObjectA: 0.017DEC: 50.2413KMAG: 10.961KOI: 72.01MSTAR: 1.03PER: 0.8374903RA: 19.04529ROW: 31RPLANET: 1.38RSTAR: 1T0: 64.57439TPLANET: 1903TSTAR: 5627UPER: 0.0000015UT0: 0.00026
I should also add that in chrome you need the CORS plugin. I didn't dig into the issue quite as indepth as I should for angular. I found a base html can get around these CORS restrictions, this is just a work around until I have more time to understand the issue.
After lots of looking around. The best local solution I found for this is the npm module CORS-anywhere. Used it to create AngularJS AWS Cloudsearch Demo.

Categories