I'm trying to process the returned JSON result from the request
so I need to expand its scope outside this request call.
To do that I declared data variable with an empty string and assign the result to this data but it doesn't print the result.
How can I accomplish this?
module.exports = function(callback) {
var request = require("request")
var url = "http://sheetsu.com/apis/94dc0db4"
var data = "";
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
callback(body)
data = body;
}
})
console.log(data);
}
This is classic async confusion : your console.log call will happen before the http request callback.
Your script is executed in this order:
request() is executed
console.log(data)
request() callback function, where you asign data a value
If you want to print data, you must do it inside the request callback function. The async module, is very useful when performing async tasks, specially if you need to perform tasks in a specific order and use the data from this requests.
Related
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 7 years ago.
Below is my code which make http request to a web server having host 78.154.17.70, port 8080 and path /csrftoken.json.
I use request.get to get the data from the server. I am able to fetch the data, which is Json data in the following format:
{
"apiVersion": "1.0",
"data": {
"csrf": "ajbgajbgjabbjbjbab"
}
}
I declared two variables var CSRFTokenValue; and var respJson; globally. Inside request.get, I use these variables as: respJson store the parse data and CSRFTokenValue store the
"csrf": "ajbgajbgjabbjbjbab" token value as "ajbgajbgjabbjbjbab"
means CSRFTokenValue will store "ajbgajbgjabbjbjbab" in it.
Now when i log CSRFTokenValue inside the request.get it will give me the "ajbgajbgjabbjbjbab" but when I log it outside it will give me undefined .
I need CSRFTokenValue to use in the quesryString inside the request.post to post the data.
I don't know how to get the tokenValue globally??
var request = require('request');
var CSRFTokenValue;
var respJson;
request.get('http://78.154.17.70:8080/csrftoken.json', function (e, res, body){
respJson = JSON.parse(body);
CSRFTokenValue = respJson.data.csrf;
console.log('GET success:' + CSRFTokenValue);
});
console.log('GET token Globaly:' + CSRFTokenValue);
request.post('http://78.154.17.70:8080/Login/post.json?_csrf=' + CSRFTokenValue, {
'name' : 'name',
'password' : 'pass'
}, function (res) {
console.log('success');
});
This is because when you make your initial request it is being done asynchronously. The program moves right to the next statement in your control flow while your request is done in the background. When the request finishes, CSRFTokenValue will be set but you're printing out the value before the request has finished so it's undefined.
Try this instead.
var request = require('request');
request.get('http://78.154.17.70:8080/csrftoken.json', function (e, res, body){
var respJson = JSON.parse(body);
var CSRFTokenValue = respJson.data.csrf;
console.log('GET success:' + CSRFTokenValue);
request.post('http://78.154.17.70:8080/Login/post.json?_csrf=' + CSRFTokenValue, {
'name' : 'name',
'password' : 'pass'
}, function (res) {
console.log('success');
});
});
This will make your second request once you've gotten the token needed from your first one.
Also, take a look into asynchronous programming.
The line,
console.log('GET token Globaly:' + CSRFTokenValue);, would execute immediately, bypassing your asynchronous call, request.get('http://78.154.17.70:8080/csrftoken.json'.... That's the reason CSRFTokenValue is undefined, as in the declaration, you did not initiate it with a value.
Use a promise to run your request.post('http://78.154.17.70:8080/Login/post.json?_csrf='.... Simply run that within request.get when the AJAX call is successful.
I'm doing a JSON call like this:
var desc = getItemDescriptions(xxx);
function getItemDescriptions(xxx) {
var url = "xxx;
var info = {};
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
info ["..."] = body.result[xxx].yyy;
info ["..."] = body.result[xxx].yyy;
info ["..."] = body.result[xxx].yyy;
info ["..."] = body.result[xxx].yyy;
info ["..."] = body.result[xxx].yyy;
}
})
return info;
}
My Problem is, the JSON request need some time to get response back... and my function doesn't wait for this response. The Function returns the empty array without waiting.
How can i wait for response and then return the filled array?
thx
Its not like executing fast, it is the way javascript runs statement after statement. To get the data you need to do that in success callback function, the data would be available only when the server response comes back as its asynchronous call by the time response comes your javascript executes next statements.
Juhana already linked to you the best place to get a good solution. How to return the response from an async call
A quick and dirty hack would be (if request is a jQuery-like Ajax-function) to make the request synchronus.
This might be done by adding async: false to the first parameter passed to request:
request({ url: url,json: true, async: false}, function ....
That way return info will be executed AFTER your request has finished.
HTH
Georg
I'm a bit of a newbie to NodeJS, but I've looked around all over and can't seem to find a solution to my problem below. I'm sure it's something simple, but thanks in advance for all help you can give me!
I'm trying to make a simple JSON scraper via NodeJS. All I need is for JSON to be stored to a variable. The problem is, I'm using Require, and their example just logs it to console. I've tried adding a variable after it's logging to the console, but I'm just getting undefined. Here's my code below, it's pretty simplistic so far :)
// var jsonVariable; Doesn't work, shown as a test
function getJSON(url){
var request = require("request")
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body) // Print the json response
//return body; This doesn't work, nor does making a global variable called json and assigning it here. Any ideas?
//jsonVariable = body; // This also doesn't work, returning undefined even after I've called the function with valid JSON
}
})
}
Once again, thanks so much for any help you can give me :)
The problem is that the request method is asynchronous, but you're trying to synchronously return a result. You'll need to either make a synchronous request (which doesn't appear to be possible with the request package you're using), or else pass a callback function to be called when the request responds successfully. e.g.:
var request = require("request")
function getJSON(url, callback) {
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
callback(body);
}
});
}
getJSON('http://example.com/foo.json', function (body) {
console.log('we have the body!', body);
});
If you use 'return body' where does it return to? That function is being called as a parameter to the request() function. You also cannot define a variable in your anonymous function because you will not have access to it outside of that scope.
What you need to do is define a variable outside of function getJSON() and then save body to that.
e.g.,
var result;
function getJSON(url){
var request = require("request")
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
result = body;
}
});
}
I'm using express and request to turn a site's html into json, then returning it. For example:
app.get('/live', function(req,_res){
res = _res;
options.url = 'http://targetsite.com';
request(options,parseLive);
});
function parseLive(err, resp, html) {
var ret = {status:'ok'};
-- error checking and parsing of html --
res.send(ret);
}
Currently I'm using a global var res to keep track of the return call, but this fails when multiple requests are made at the same time. So, I need some way of matching return calls from express to their callbacks in request.
How might I do this?
Use a closure.
Pass the variable to a function. Return the function you want to pass to request from that function.
app.get('/live', function(req,_res){
options.url = 'http://targetsite.com';
request(options,parseLiveFactory(res));
});
function parseLiveFactory(res) {
function parseLive(err, resp, html) {
var ret = {status:'ok'};
-- error checking and parsing of html --
res.send(ret);
}
return parseLive;
}
I have a little trouble with an Node application, the problem is: I have an Script in a web site "x" and this script calls a function that is on another server (like analytics), I'm calling the function with ajax and when the function returns the data, happen some curious, when I check the network with Developer Tools in Chrome, the callback shows the response like I wanted in JSON format, but not show me data. My code:
var xml2js = require('xml2js'),
http = require('http'),
request = require('request');
var parserController = function (aw){
console.log('Parse Controller load');
aw.get('/ads/:keyword/:sid/:pid/:count', function (req,res){
res.setHeader('Content-Type', 'application/json');
request('http://'+req.params.sid+'.'+req.params.pid+'.autoweb-xml.com/feed?&sid='+req.params.sid+'&auth=2Al5&subid=&q='+req.params.keyword+'&ip=127.0.0.1&ua=Mozilla/5.0%20(Windows%20NT%206.1;%20WOW64;%20rv:26.0)%20Gecko/20100101%20Firefox/26.0&ref=awebads.lan&count='+req.params.count+'&state=&city=', function (error, response, body) {
if (!error && response.statusCode == 200) {
var parser = xml2js.parseString;
var data = '';
parser(body,{explicitRoot : false}, function (err, result){
if(!err){
data = result;
dataP=data.results[0];
dataS=dataP.sponsored[0];
console.log(dataS.listing);
return res.send(dataS.listing);
}
else
{
console.log(err);
}
})
}
})//en del request
});
};
and my call function is:
var xhr = $.ajax({
type:'GET',
url:'http://HOST/ads/'+configParams.keyword+'/'+configParams.envSource+'/'+configParams.envPublisher+'/'+configParams.envCount,
dataType : 'jsonp',
async: false,
crossDomain : true
})
xhr.done(function (data){
console.log(data);
data.forEach(function(item){
window.collections.ads.add(item);
});
}).fail(function (err) {
//console.log('failed');
//console.log(err)
});
when I display the data in the console, this part show me the XMLHTTPRequest, thanks in advance for your help
You are sending JSON:
the callback shows the response like I wanted in JSON format
… but the client is expecting JSON-P
dataType : 'jsonp',
Either:
Tell the client to expect JSON (or just remove the dataType line and let it use the Content-Type header) and set Access-Control-Origin on the response headers to give the site permission to access it cross-domain or
Send JSON-P back instead (look at callback in the query string, send Content-Type: application/javascript (not JSON!), and return callback_value(your_json); as the response body.
In case of jsonp you need a callback function and then return your response in that callback.