I would like to replace the if(body.toString().indexOf("404") !== 0) block with some generic error handling code but I can't seem to see where it throws an error when the target host is down. So far, this is the only hacky method I've managed to put together that works.
app.get('/', function(req, res){
var sites = ["foo.com", "bar.com"];
var returnObj = [];
var index = 0;
getSites(index);
// Recursively add data from each site listed in "sites" array
function getSites(index) {
if(index < sites.length) {
var url = sites[index];
var _req = http.get({host: url}, function(_res) {
var bodyChunks = [];
_res.on('data', function(chunk) {
bodyChunks.push(chunk);
}).on('end', function() {
var body = Buffer.concat(bodyChunks);
if(body.toString().indexOf("404") !== 0) {
returnObj.push(JSON.parse(body));
}
getSites(++index);
});
});
_req.on('error', function(e) {
console.log('ERROR: ' + e.message);
});
} else {
res.json(returnObj);
res.end();
}
}
});
You can check the status code of the response.
if(_req.statusCode === 200) {
//Response okay.
}
Here's a list of the status codes.
Related
So this how the app should work: with a Node.js script I call the coincap.io api, and I store the response of the various request in different files. Here is the script:
var request = require("request");
var fs = require("fs");
var cors = require("cors");
var parseString = require("xml2js").parseString;
var coinstore = [];
var endpoint = ["coins", "map", "front", "global"];
for (i = 0; i < endpoint.length; i++) {
request("http://coincap.io/" + endpoint[i], function(err, response, body) {
console.log("error", Error);
console.log("statusCode: ", response && response.statusCode);
//console.log("body: ", JSON.stringify(body));
var xml = body;
parseString(xml, function(err, result) {
console.log(xml);
coinstore.push(xml);
});
fs.writeFile("D:/bibblebit/response" + response.request.path.replace(/\//g, "") + ".json", coinstore,
function(err) {
if (err) {
console.log(err);
} else {
console.log("salvato!");
}
});
});
};
I then let the user make custom calls and retrieve data from those files.
Here is a working call:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
console.log("pronto!");
var alldata = [];
alldata.push(xhr.response);
var obj = JSON.parse(alldata);
console.log(obj);
document.getElementById("api-container").innerHTML += obj.altCap;
} else {
console.log("try again");
}
}
xhr.open("GET", "http://127.0.0.1:8081/responseglobal.json", true);
xhr.send(null);
This works because the file responseglobal.json has a single object.
Changing the last snippet into this one:
document.getElementById("api-container").innerHTML += obj.mktcap;
}
else {
console.log("try again");
}
}
xhr.open("GET", "http://127.0.0.1:8081/responsefront.json", true);
xhr.send(null);
returns a self explanatory error:
[Visualizza/nascondi dettagli messaggio.] SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data at line 1 column 264 of the JSON data
Every comma separating objects results in an unexpected character, which means I am not able to create one object for every object in the file or at least read a file with more than one object. What am I missing?
I may have missed the right approach. I can't find on the net a fitting explanation, since the questions I was able to find refer to manually created objects or so specific scenarios to become useless in my case to a different extent.
This is the server side script:
var request = require("request");
var fs = require("fs");
var cors = require ("cors");
var parseString = require("xml2js").parseString;
var endpoint = ["coins", "map","front", "global"];
var i = 0;
for (i=0 ; i<endpoint.length ; i++){
request("http://coincap.io/"+endpoint[i], function (err, response, body){
var coinstore = [];
console.log("error", Error);
console.log("statusCode: ", response && response.statusCode);
var xml =JSON.stringify(body);
parseString(xml, function (err, result){
console.log(xml);
coinstore.push(xml);
});
fs.writeFileSync("/response"+ response.request.path.replace(/\//g, "")+ ".json", coinstore, function(err){
if (err){
console.log(err);
}
else {
console.log("salvato!");
}
});
});
};
And this one is the client-side one:
var queries = [ "global", "coins", "map","front"];
for(i=0; i<queries.length; i++) {
pronto(i);
}
function pronto(i) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState == XMLHttpRequest.DONE) {
console.log("pronto!");
var obj = JSON.parse(xhr.response);
//console.log(obj);
document.getElementById("api"+i+"-container").innerHTML+=obj;
console.log("stampato: "+ i);
} else {
console.log("bucato");
}
}
xhr.open("GET", "response"+ queries[i] +".json", true);
xhr.send(null);
}
They might not be the best solutions, but they work out.
I got an array of strings and I'd like to check if any of these strings contain a certain substring.
The following code is an example of what I need to achieve: the function gets a message from an user and searches through a series of URLs the one that contains the user's message in the title:
var redditSubModule = "node";
var http = require('https');
var url = "https://www.reddit.com/r/soccerstreams/new/.json";
var i = 0;
var subject = (ctx.message.text).substring(8);
var request = http.get(url, function(response) {
var json = '';
response.on('data', function(chunk) {
json += chunk;
});
response.on('end', function() {
var redditResponse = JSON.parse(json);
redditResponse.data.children.forEach(function(child) {
if(child.data.domain !== 'self.node') {
url = child.data.url;
console.log('URL : ' + url);
if (url.indexOf(subject) > -1) {
console.log('URL : ' + url);
} else {
console.log("nothing...");
}
i++;
}
});
})
});
request.on('error', function(err) {
console.log(err);
});
If you try and fill subject with "USA" (because there's a thread with that string in the title) the indexOf doesn't seem to work and it prints a list of "nothing..."
Logging the typeof url gives string as type so I don't know what is going on here...
What am I doing wrong ?
You can use array.prototype.find and array.prototype.includes:
var strs = ["aaa", "xxx", "yyy_leon"];
var search = "leon";
var found = strs.find(s => s.includes(search));
if (found) {
console.log("found: ", found);
} else {
console.log("nothing");
}
Ok, I do not understand what is going here, works locally but not on my server.
I have a angular controller that post to my node server.
each time I try and run the function that triggers the post I get
POST http://www.mysite.co.uk/mm3/back-end/savephotos 404 (Not Found)
Im honestly lost, ive rewritten the post 5 times I cant find the problem.
If anyone can see where ive gone wrong please help.
angular controller
mm3\js\controller.js
//all photos've been pushed now sending it to back end
$timeout(function () {
$http.post('back-end/savephoto', $scope.photosToPhp).then(function (success) {
$scope.generating = false;
$scope.generateBtn = 'Generate';
//creating mock up gallery
for (var x = 0; x < success.data.photos; x++) {
var file = '/mm3/tmp/' + success.data.folder + "/out" + x + ".png";
$scope.gallery.push(file);
}
$scope.photosToPhp = [];
}, function (error) {
});
}, 800);
then my node back-end
UPDATED:
So I have added a few console logs in my function to see where its going wrong and where it is getting to.
I keep getting:
test 1 function started error saving photo
mm3\back-end\controller.js
app.post('/mm3/back-end/savePhoto', function (req, res) {
console.log('test 1 function started');
var folder = Math.random().toString(36).substr(2, 20);
var photos = req.body;
var counts = 0;
var callback = function(counts){
if(counts < photos.length){
saveBase64(photos[counts],folder,counts,callback);
console.log('test 2 save photo');
}else{
var counts = 0;
var response = {"folder":folder, "photos": photos.length};
console.log('test 3 save photo else');
res.send(response)
}
};
saveBase64(photos[counts],folder,counts,callback);
});
app.post('/mm3/downloadZip', function(req, res){
var photos = req.body;
var out = photos[0];
var test = out.split('/');
var loc = test.pop();
var end = test.join('/');
console.log('test 3 function Generate zip file');
console.log(end);
var outName = '/' + end +'/mm3/MockUp.zip';
var output = fs.createWriteStream(outName);
var archive = archiver('zip', {store: true });
var zip = function(photos, f){
for(var t = 0; t < photos.length; t++){
var file = 'mockUp'+ t +'.jpg';
var from = '/var/www/html' + photos[t];
archive.file( from, { name: file });
}
f();
};
output.on('close', function() {
var photos = req.body;
var out = photos[0];
var test = out.split('/');
var loc = test.pop();
var end = test.join('/');
res.send(end + '/MockUp.zip');
console.log('archiver has been finalized and the output file descriptor has closed.');
});
archive.on('error', function(err) {
throw err;
});
archive.pipe(output);
zip(photos, f);
function f(){
archive.finalize();
}
});
function saveBase64(photo,folder, counts, callback){
var result = photo.split(',')[1];
var path = '/mm3/tmp/' + folder;
var filename = path + "/out"+ counts + ".png";
mkdirp( path, function() {
fs.writeFile(filename, result, 'base64', function(error){
if (error) {
console.log('error saving photo');
}else{
console.log('photo saved');
counts ++;
callback(counts);
}
});
});
}
I think this is the problem:
app.post('back-end/savephoto', function (req, res) {
// skipped some lines
});
change it to
app.post('/back-end/savephoto', function (req, res) {
// skipped some lines
});
In Angular, the below:
$http.post('back-end/savephoto......
Becomes:
$http.post('/back-end/savephoto.....
In Node, the below:
app.post('back-end/savephoto.....
Becomes:
app.post('back-end/savephoto....
Then, you need to add a console.log under the Node route to see if it even is executed. This will narrow it down. Also, you can remove the $http.post call outside of the timeout to eliminate the obvious.
Let me know how you get on.
Shayan
So I have read a lot of the different answers about asynchronous functions on here but I think I am over thinking my problem, or I have been staring at it just to long and I cant figure it out. So your help is greatly appreciated.
So I am parsing a csv file and then trying to get the lat/long through another api. but I cant access the lat/lng outside of the function. below is my code I have commented it to the best of my ability please let me know if there are any questions or a much better way to do this.
Thanks,
var location = []
function run() {
http.get(url, function(res) {
if(res.statusCode === 200) {
res.pipe(parse(function(err, data) {
for(i = 1; i < data.length; i++) {
var info = data[i];
passLoc = info[6].replace('block ', '')
passLoc = passLoc.replace(/ /g, "+")
getLoc(passLoc, function(loc) {
location.push(loc);
//If I console.log(location) here I get all the info I want but.....it is printed 100 times becuase it is printed for each i in data.length
})
}
console.log(location) // loging this here gives me an empty array
}))
}else {
console.error('The address is unavailable. (%d)', res.statusCode);
}
})
}
function getLoc(x, callback) {
var url = "http://geodata.alleghenycounty.us/arcgis/rest/services/Geocoders/EAMS_Composite_Loc/GeocodeServer/findAddressCandidates?Street=" + x + "&City=Pittsburgh&State=PA&ZIP=&SingleLine=&outFields=&outSR=4326&searchExtent=&f=pjson";
http.get(url, function(res) {
var data = '';
res.on('data', function(chunk) {
data += chunk;
});
res.on('end', function() {
var d = JSON.parse(data);
var obj = d.candidates;
if(obj != '') {
var loc = obj[0].location
var lat = loc.x
var lng = loc.y
var location = [lat, lng];
callback(location)
} else {
callback(x);
}
});
res.on('error', function(err) {
callback("error!")
});
});
}
Your code tries to synchronously consume asynchronous data -- you're synchronously trying to access the results (location) before any of the asynchronous operations have finished.
As you have multiple async operations running in parallel, you can make use of async.parallel to aid in controlling the asynchronous flow:
var async = require('async');
function run() {
http.get(url, function(res) {
if(res.statusCode === 200) {
res.pipe(parse(function(err, data) {
// array of async tasks to execute
var tasks = [];
data.slice(1).forEach(function(info) {
var passLoc = info[6].replace('block ', '').replace(/ /g, '+');
// push an async operation to the `tasks` array
tasks.push(function(cb) {
getLoc(passLoc, function(loc) {
cb(null, loc);
});
});
});
// run all async tasks in parallel
async.parallel(tasks, function(err, locations) {
// consume data when all async tasks are finished
console.log(locations);
});
}));
}else {
console.error('The address is unavailable. (%d)', res.statusCode);
}
});
}
Also, for loops don't create a scope, so I've swapped it by a forEach in order to scope the info and passLoc variables inside each iteration.
Here's a slightly more condensed version using ES5's Array#map:
var async = require('async');
function run() {
http.get(url, function(res) {
if(res.statusCode === 200) {
res.pipe(parse(function(err, data) {
async.parallel(
// map data items to async tasks
data.slice(1).map(function(info) {
return function(cb) {
var passLoc = info[6].replace('block ', '').replace(/ /g, '+');
getLoc(passLoc, function(loc) {
cb(null, loc);
});
};
}),
function(err, locations) {
// consume data when all async tasks are finished
console.log(locations);
}
);
}));
} else {
console.error('The address is unavailable. (%d)', res.statusCode);
}
});
}
How would I handle a situation where the file does not exist on the server, or is unable to connect with the server to get the file?
As of the code below, the file download still occurs, and the file is empty.
var https = require('https');
var fs = require('fs');
var exec = require('child_process').exec;
var file = fs.createWriteStream('mediaserver_setup.exe');
var len = 0;
var req = https.get(url + 'appdata/update_setup.exe', function (res) {
if (res.statusCode === 404) {
alert('problem with request:');
}
res.on('data', function (chunk) {
file.write(chunk);
len += chunk.length;
var percent = (len / res.headers['content-length']) * 100;
progressLoading.val(percent);
});
res.on('end', function () {
setTimeout(function () {
file.close();
}, 500);
});
file.on('close', function () {
win.close();
exec('update_setup.exe');
});
});
req.on('error', function (err) {
alert('problem with request: ');
});
Use the error event for requests, or check the status code of the response:
var https = require('https');
var req = https.get(options, function(res) {
// use res.statusCode
if (res.statusCode === 404) {
// example for checking 404 errors
}
});
req.on('error', function(err) {
// an error has occurred
});