I'm new to node.js, and I'm trying to call a service, parse its data and return it as part of a view. I can't seem to get the request to block until the response is complete. The console always logs 'wrong' before 'right' (returning the 1,2,3 array). What am I missing?
app.js
var reading = require('./reading');
app.get('/reading', function(req, res){
res.render('reading/index.stache',
{
locals : { ids : reading.list},
partials : {
list : '{{#ids}}{{.}}<br />{{/ids}}'
}
});
});
reading.js
var request,
http = require('http'),
host = 'google.com',
path ='/';
var list = function(){
var connection = http.createClient(80, host),
request = connection.request(path);
request.addListener('response', function(response){
var data = '';
response.addListener('data', function(chunk){
data += chunk;
});
response.addListener('end', function(){
console.log('right')
//var results = JSON.parse(data);
// i need results from json
return [88234,883425,234588];
});
});
request.end();
console.log('wrong');
return [1,2,3];
}
module.exports.list = list;
Of course you can't get the request to block until the response is back.
That's because there is communication latency between sending the request of and getting the response back. It would be stupid to wait and do nothing whilst that latency is happening.
Use callbacks and asynchronous control flow.
var list = function(callback){
var connection = http.createClient(80, host),
request = connection.request(path);
request.addListener('response', function(response){
var data = '';
response.addListener('data', function(chunk){
data += chunk;
});
response.addListener('end', function(){
console.log('right')
// USE A CALLBACK >:(
callback([88234,883425,234588]);
});
});
request.end();
}
If you wan't to run anything in sync have a look at the sync module. It's based on fibers.
Related
I'm trying to fetch json from an api but only half of the response is received. So how to get the full response?
var request = require('request');
var url_to_check = 'http://example.com/api/test';
request.get(url_to_check).on('data', function(data) {
// Only half of the data is printed (8192). Remaining bytes are lost.
console.log(data.toString());
})
Your code is correct the only mistake you made is that you are streaming request data so you won't get whole data on event 'data' if a response is large. You will have to collect chunk and consolidate on event 'end'. check this code snippet
var request = require('request');
var url = 'https://reqres.in/api/users';
var req = request.get(url)
var data = []
req.on('data',function(chunk){
data.push(chunk))
})
req.on('end',function(){
console.log(Buffer.concat(data).toString())
})
And If you don't want to stream and pipe data and also response size is small then you can try this:
request.get(url, function(err, response, responseBody) {
if (!err) {
// var jsonRes = JSON.parse(JSON.stringify(response))
// responseBody = jsonRes.body
console.log(responseBody)
} else {
// handle error here
}
})
Im a newbie with node.js and i'm trying to output some data to html.
My code works when I use console.log but not when I use response.end.
When I use response.end I only see on record while when I use console.log I get to see all the records
See my full code below:
var http = require('http');
var formOutput;
var WooCommerceAPI = require('woocommerce-api');
// Initialize the WooCommerceAPI class
var WooCommerce = new WooCommerceAPI({
//url: 'http://example.com', // Your store url (required)
});
function handleRequest(response) {
// GET example
WooCommerce.get('products', function (err, data, res) {
//console.log(res);
//var fs = require('fs');
//var jsonContent = JSON.parse(JSON.stringify(res, null, 4))
var jsonContent = JSON.parse(res)
for (var i = 0; i < jsonContent["products"].length; i++) {
var name = jsonContent["products"][i];
// this works well and I can output all records
//console.log(name['title']);
//console.log(name['id']);
//console.log(name['sku']);
//console.log(name['regular_price']);
//response.writeHead(200, { 'Content-Type': 'text/html' });
//res.end(name['id']);
formOutput = name['regular_price'];
//formOutput = '<h1>XYZ Repository Commit Monitor</h1>';
//response.write();
//Only get one record
response.end(formOutput);
//response.write('<html><head></head><body>');
//response.end("test");
//response.end('</body></html>');
}
});
//response.end(formOutput);
}
http.createServer(function (req, response) {
if (response.url === '/favicon.ico') {
response.writeHead(404);
response.end();
} else {
response.writeHead(200, { 'Content-Type': 'text/html' });
}
//code here...
handleRequest(response);
// response.end(formOutput);
}).listen(1337, "localhost");
console.log("Server running at http://localhost:1337/");
With Express, response.end() closes the communication channel after one call so only one element will be sent to the user. Don't use end() to send data, in your case, use response.json() (or send()) ONCE after you built the data array.
var dataToSend = [];
for (var i = 0; i < jsonContent["products"].length; i++) {
// build an array of data to send here
}
response.json(dataToSend);
On a side note, don't use response.end() unless you want to end the communication explicitly. response.json() and response.send() already close the channel when needed.
I have an http server with a handleRequest callback that runs another script in vm.runInNewContext for each request. The script that runs inside vm.runInNewContext makes some asynchronous http post requests and writes the server response only after getting the responses from the posts.
As a result, the code of handleRequest callback ends before the server response is written.
Is it safe? or is there a way to avoid this situation?
Here is some code:
var server = http.createServer(handleRequest);
server.listen(8080);
var handleRequest = function (request, response) {
// get request data...
var context = {
ServerRequest : request,
ServerResponse : response
};
var stringScript = // a string with the script that posts data
var script = vm.createScript(stringScript);
script.runInNewContext({ context: context });
}
the script string does this:
var request = require('request');
var options = {....}
var req = request.get(options);
req.on('response', function (res) {
var chunks = [];
res.on('data', function(chunk) {
chunks.push(chunk);
});
res.on('end', function() {
var buffer = Buffer.concat(chunks);
var encoding = res.headers['content-encoding'];
if (encoding == 'gzip') {
zlib.gunzip(buffer, function(err, decoded) {
// set response headers and write the response
context.ServerResponse.end(decoded.toString());
});
} else if (encoding == 'deflate') {
zlib.inflate(buffer, function(err, decoded) {
// set response headers and write the response
context.ServerResponse.end(decoded.toString());
})
} else {
// set response headers and write the response
context.ServerResponse.end(buffer.toString());
}
});
});
Simple solution: Return a promise (e.g. use the Q-library) from the VM-script.
script.runInNewContext will return whatever you return from the VM-script. That way you have a "callback" for when the VM code finishes.
// Script for VM
// I simplified it. Just resolve or reject the promise whenever you are done with your work
'use strict';
var defer = q.defer();
doABarrelRoll(function() {
defer.resolve('RESULT');
});
defer.promise; // This line will return the promise.
When returning a value from a VM-script, you do not need any return construction. Just write the thing you want and let the magic happen.
// Script for current context
'use strict';
var server = http.createServer(handleRequest);
server.listen(8080);
var handleRequest = function (request, response) {
// get request data...
var context = {
ServerRequest : request,
ServerResponse : response
};
var stringScript = // a string with the script that posts data
var script = vm.createScript(stringScript);
var prom = script.runInNewContext({
context: context,
q: require('q'),
});
prom.done(function ($result) {
console.log('VM finished with result: ' + $result);
});
}
i did this tutorial node.js eventEmitter, it worked nicely. I added a method that uses http.request to get data, which works and emit the data.
the problem is that the listener doesn't catch the event !
can someone help ?
code :
var events = require('events');
var util = require('util');
var http = require('http');
//http request options, it query the twitter api and get the public timeline, works!
var options = {
hostname : 'api.twitter.com',
port : 80,
method : 'get',
path : '/1/statuses/public_timeline.json?count=3&include_entities=true'
}
// The Thing That Emits Event
Eventer = function(){
events.EventEmitter.call(this);
//tutorial examples
this.kapow = function(){
var data = "BATMAN"
this.emit('blamo', data);
}
//tutorial examples
this.bam = function(){
this.emit("boom");
}
//my method
this.GetTweetList = function(){
var tweets = "";
var req = http.request(options, function(response){
var body = "";
response.on('data',function(data){
body += data;
});
response.on('end', function(){
tweets = JSON.parse(body);
this.emit("tweets", tweets);
util.puts('!!!!!!!!!! got some data !!!!!!!!!! \n');
});
});
req.end();
}
};
util.inherits(Eventer, events.EventEmitter);
// The thing that listens to, and handles, those events
Listener = function(){
//tutorial examples
this.blamoHandler = function(data){
console.log("** blamo event handled");
console.log(data);
},
//tutorial examples
this.boomHandler = function(data){
console.log("** boom event handled");
}
//my listener method
this.GetTweetListHandler = function(data){
console.log("** tweets event handled");
util.put(data);
util.puts('!!!!!!!!!! got some data in listener !!!!!!!!!! \n');
}
};
// The thing that drives the two.
//instanciating the object and liking the methodes
var eventer = new Eventer();
var listener = new Listener(eventer);
eventer.on('blamo', listener.blamoHandler);
eventer.on('boom', listener.boomHandler);
eventer.on('tweets', listener.GetTweetListHandler);
//calling the methodes
eventer.kapow();//works
eventer.bam();//works
setInterval(eventer.GetTweetList, 2000);
//eventer.GetTweetList();// still waiting but the eventer display that he got the data
Hard one to spot ...
The problem is the this pointer from this.emit("tweets", tweets);. You are doing this call from within an anonymous callback passed to response.on, so this does not represent the Eventer object that you created.
To solve it, you need to "save" the this pointer (a common practice).
var tweets = "";
var self = this;
....
self.emit("tweets", tweets);
There is a post: How do I set a timeout for client http connections in node.js
but none of the answer will work.
So, I have the code like that:
var remote_client = http.createClient(myPost, myHost);
var path = '/getData?';
var param = { };
var request = remote_client.request("POST", path,);
// error case
remote_client.addListener('error', function(connectionException){
console.log("Nucleus Error: " + connectionException);
next(connectionException);
});
request.addListener('response', function (response) {
response.setEncoding('utf-8');
var body = '';
response.addListener('data', function (chunk) {
// get the result!
});
});
request.end();
The biggest problem is that the url that I'm connection to may timeout. Therefore, I would like to set a timeout, like 15 secs. If so, trigger a listener.
However, I haven't seen any timeout features in the documentation for http.createClient. Please advise. Thanks. :)
var foo = setTimeout(function() {
request.emit("timeout-foo");
}, 15000);
// listen to timeout
request.on("timeout-foo", function() { });
request.addListener('response', function (response) {
// bla
// clear counter
clearTimeout(foo);
});
Just run the counter yourself.