Technically this is my first try in nodejs and frankly I am not sure if I am doing it right. I am creating a local server that will stream the output from a distant server. However, when I run my code and I enter a URL in the browser, the program fails with the following message:
events.js:45
throw arguments[1]; // Unhandled 'error' event
^
Error: ENOTFOUND, Domain name not found
at IOWatcher.callback (dns.js:74:15)
The URL I used was: 127.0.0.1:9000/http://www.yahoo.fr. And in the browser I had the following message:
No data received
Unable to load the webpage because the server sent no data.
Here are some suggestions:
Reload this web page later.
Error 324 (net::ERR_EMPTY_RESPONSE): The server closed the connection without sending any data.
Any help is greatly appreciated.
Here is the code:
var base, dest, node_client,
count = 0,
url = require('url'),
util = require('util'),
http = require('http'),
http_client = require('http'),
request = require('request'),
events = require('events'),
httpProxy = require('./lib/node-http-proxy'),
data_emitter = new events.EventEmitter();
httpProxy.createServer(9000, 'localhost').listen(8000);
http.createServer(function (req, res) {
if(!count)
{
base = url.parse(req.url).pathname;
node_client = http_client.createClient(80, base);
count++;
} else {
dest = req.url.substr(1, req.url.length -1);
}
request = node_client.request("GET", dest, {"host": base});
request.addListener("response", function (response) {
var body = "";
response.addListener("data", function (data) {
body +=data;
});
response.addListener("end", function () {
var out = JSON.parse(body);
if(out.length > 0) {
data_emitter.emit("out", out);
}
});
});
// request.close();
var listener = data_emitter.addListener("data", function(out) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(JSON.stringify(out));
res.close();
});
}).listen(9000);
Wild guess : your browser automatically requests 127.0.0.1:9000/favicon.ico and your program then tries to resolve favicon.ico which obviously fails and makes your program crash before it can send any data for the real request.
Why such tangled code?
This is a scenario where it makes sense to avoid nested callbacks, and use named functions. If you refactor the code, then people are more likely to be help you.
Can you do console.log(out) in your listener callback? Let us know if Node.js has any response data to return.
Well, for any newbie like me in this area, here is how I solved it. It's not clean and can be implemented in better way. Feel free to change, give suggestions.
Code:
var url = require('url'),
http = require('http'),
request = require('request'),
httpProxy = require('./lib/node-http-proxy'),
des = '',
util = require('util'),
colors = require('colors'),
is_host = true;
httpProxy.createServer(9000, 'localhost').listen(8000);
var server = http.createServer(function (req, res) {
var pathname = '';
if(is_host) {
dest = req.url.substr(0, req.url.length -1);
pathname = dest;
is_host = false;
} else {
pathname = req.url.substr(0, req.url.length);
if(pathname.charAt(0) == "/") {
console.log('new request');
console.log(pathname);
pathname = dest + pathname;
}
}
console.log(pathname);
request.get({uri: pathname}, function (err, response, html) {
res.end(html);
});
console.log('fetched from ' + pathname);
});
server.listen(9000);
Related
I am facing problem of write after request end in nodejs :
I have a server.js file , which sends request to other js file (say abc.js) which sends response back to server.js file and then server.js file writes the resoponse and then end response.
my problem is if I write response in abc.js and end it there only it works fine, but if it is in sererconf.js it doesn't.
Let me make it clear that I get this bug only when i send 20-30 requests at a time. I want to know the logic behind it, I searched a lot, but no nice answer found, any help will be appreciated.
server.js full code:
/* create HTTP server */
var httpd = http.createServer(function(req, res) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.writeHead(200, {"Content-Type" : "application/json"});
}).listen(3800);
/* send request to the file mentioned in url*/
httpd.on('request', function(req, res) {
urll = __dirname + '/..' + req.url;
fs.exists(urll, function (exists) {
if(exists){
var server = require(urll);
server.get(req,res);
}
});
module.exports = {
result : function(result){
if(Array.isArray(result)){
for(var key in result){
result[key] = JSON.parse(result[key]);
}
}
result = JSON.stringify(result);
res.write(result ,function(err) { if(!err) res.end(); });
},
};
});
**apps.js code**:
var constants = require('./lib/constant.js');
var APP_PATH = constants.APP_PATH;
module.exports = {
get : function(req) {
req.on('data', function(chunk) {
var hash = chunk;
hash = JSON.parse(hash);
var id = hash.id;
dirPath = APP_PATH + id;
fs.exists( dirPath, function (exists) {
if(exists)
read_app_dir(dirPath);
else
taskDone([]);
});
});
}
};
function read_app_dir(app_dir){
fs.readdir(app_dir,function(err, list){
if (err) {
httpd.log.info('cannot read apps dir at s_apps = '+err);
}else{
create_new_obj(list,app_dir);
}
});
}
function create_new_obj(list, app_dir){
appFilesObj = [];
var i = 0;
list.forEach(function(file) {
i=i+1;
file = app_dir +'/' +file;
appFilesObj.push(file);
if(i == Object.keys(list).length)
read_app_files(appFilesObj);
});
}
function read_app_files(appFilesObj,app_dir){
var apps = [];
var i = 0;
if(Object.keys(appFilesObj).length > 0){
appFilesObj.forEach(function(appfile) {
read_file(appfile,function(data){ i=i+1;
apps.push(data);
if(i == Object.keys(appFilesObj).length)
taskDone(apps);
});
});
}else{
taskDone([]);
}
}
function read_file(file,callback){
fs.readFile(file,'utf8', function (err, data) {
if (err)
httpd.log.info('cannot read file at s_apps = '+err);
else
callback(data);
});
}
function taskDone(apps){
var httpd = require(__dirname + '/server.js');
httpd.result(apps);
}
if I do res.write and res.end in this file in taskDone() then it works fine.
Thanks in advance :)
The problem with above code was, that I was sending back response by calling an exported function of server.js
like this:
var httpd = require(__dirname + '/server.js');
httpd.result(apps);
where result() is the function which I have exported in server.js to write response and end response
Instead of this, now I added a callback support while calling function of other files (ex-apps.js), so that I "res.write" and "res.end()" only when the actually called function gives back the response.
(I am not writing the whole code , please refer above code for difference in both)
httpd.on('request', function(req, res) {
urll = __dirname + '/..' + req.url;
fs.exists(urll, function (exists) {
if(exists){
var server = require(urll);
server.get(req,res,function(result){
res.write(result);
res.end();
});
}
});
**apps.js**
get : function(req, callback) {
req.on('data', function(chunk) {
//when task is done and taskDone() function is called I just callback() the result
function taskDone(result){
callback(result);
}
}
}
When I was sending result back by calling a function of server.js and then writing the response...I don't know how..but somehow server was getting confused in multiple requests and saying "write after end" error...while the end was called by some other user's request.
I may be wrong, but this is what I concluded from this :)
I hope this may help others.
What am I doing wrong in the code below? The left_label and right_label variables seem to always be "true", when I know I have them in the Redis set to some string. I'm assuming it's because the client.get function is successful and returns true, but how do I get it to return the actual value?
var http = require('http');
var redis = require('redis');
var client = redis.createClient(6379, 127.0.0.1);
var server = http.createServer(function (request, response) {
var left_label = client.get('left', function(err, reply) {
console.log(reply);
return reply;
});
var right_label = client.get('right', function(err, reply) {
console.log(reply);
return reply;
});
response.writeHead(200, {"Content-Type": "text/html"});
var swig = require('swig');
var html = swig.renderFile('/var/www/nodejs/index.html', {
left: left_label,
right: right_label
});
response.end(html);
});
server.listen(8000);
console.log("Server running at http://127.0.0.1:8000/");
The get call is asynchronous and must be handled that way.
A suggestion would be to combine it with a promise library such as bluebird as suggested in the NPM documentation for the redis module.
That way, we can promisify the redis module and use it in a more simple way.
var redis = require('redis');
bluebird.promisifyAll(redis.RedisClient.prototype);
and use the new async version of the get function, as below.
function getLabelValues(){
var left_promise = client.getAsync("left").then(function(reply) {
return reply;
});
var right_promise = client.getAsync("right").then(function(reply) {
return reply;
});
return Promise.all([left_label, right_label]);
}
getLabelValues().then(function(results){
//This is run when the promises are resolved
//access the return data like below
var left_label = results[0];
var right_label = results[1];
});
I have written a node.js server which creates a server and prints the output when done with an asynchronous function. While I am able to get the correct output always in the console.log. The same is not getting reflected in my response. Here is my code snippet :-
var request = require('request');
var http = require('http');
var cheerio = require('cheerio');
var url = require('url');
var Curl = require( 'node-libcurl' ).Curl;
var sleep = require('sleep');
isDone = 0;
globalImage = "";
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
var url_parts = url.parse(req.url, true);
var query = url_parts.query;
var main_url = query["link"];
if (req.url != '/favicon.ico') {
res.writeHead(200);
if(main_url != undefined ){
var position = parseInt(query["position"]);
// web_scrap()
web_scrap(main_url,position, function(image) {
console.log("Console log : " + image);
globalImage = image;
});
res.write(globalImage);
res.end("HEY");
}
}
else {//For favicon and other requests just write 404s
res.writeHead(404);
res.write('This URL does nothing interesting');
res.end();
}
}).listen(3000, '127.0.0.1');
console.log('Server running at http://127.0.0.1:3000/');
function web_scrap(url, position, callback){
// do something
callback(JSON.stringify(product));
}
Now on starting the server and accessing it in browser with parameters link and position as get, I am getting output on second or third refresh. I am getting perfect output in console.log though !
Can anyone help or guide me in this regard ?
Thanks !
From what I understand, you're loading an image from an external source, asynchronously.
Thus, your function continues to run, even though the load is not finished yet. And as your globalImage is a global variable, once it is loaded, it stays in memory, that's why you get the data after some tries.
Just move your res.write and res.end in the callback function, this way the content will be sent once the image is loaded.
web_scrap(main_url,position, function(image) {
console.log("Console log : " + image);
globalImage = image;
res.write(globalImage);
res.end("HEY");
});
Anyway, except if you want to cache your image, you should not have a globalImage variable, as it would stay in memory even though you would want it to be garbage collected. You can remove the variable and just make this:
web_scrap(main_url,position, function(image) {
console.log("Console log : " + image);
res.write(image);
res.end("HEY");
});
I'm a beginner of node.js and javascript.
I want to include external javascript file in html code. Here is the html code, "index.html":
<script src="simple.js"></script>
And, here is the javascript code, "simple.js":
document.write('Hello');
When I open the "index.html" directly on a web browser(e.g. Google Chrome), It works.
("Hello" message should be displayed on the screen.)
However, when I tried to open the "index.html" via node.js http server, It doesn't work.
Here is the node.js file, "app.js":
var app = require('http').createServer(handler)
, fs = require('fs')
app.listen(8000);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
("index.html", "simple.js" and "app.js" are on same directory.)
I started the http server. (by "bash$node app.js")
After then, I tried to connect "localhost:8000".
But, "Hello" message doesn't appear.
I think the "index.html" failed to include the "simple.js" on the http server.
How should I do?
Alxandr is right. I will try to clarify more his answer.
It happens that you have to write a "router" for your requests. Below it is a simple way to get it working. If you look forward www.nodebeginner.org you will find a way of build a proper router.
var fs = require("fs");
var http = require("http");
var url = require("url");
http.createServer(function (request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
response.writeHead(200);
if(pathname == "/") {
html = fs.readFileSync("index.html", "utf8");
response.write(html);
} else if (pathname == "/script.js") {
script = fs.readFileSync("script.js", "utf8");
response.write(script);
}
response.end();
}).listen(8888);
console.log("Listening to server on 8888...");
The problem is that nomatter what your browser requests, you return "index.html". So the browser loads your page and get's html. That html includes your script tag, and the browser goes asking node for the script-file. However, your handler is set up to ignore what the request is for, so it just returns the html once more.
Here is a working code.
There should be more cleaner simpler code, but this is very close to minimal.
This code suppose your index.html and other files are under /client dir.
Good luck.
var fs = require('fs');
var url = require("url");
var path = require('path');
var mime = require('mime');
var log = console.log;
var handler = function (req, res)
{
var dir = "/client";
var uri = url.parse(req.url).pathname;
if (uri == "/")
{
uri = "index.html";
}
var filename = path.join(dir, uri);
log(filename);
log(mime.lookup(filename));
fs.readFile(__dirname + filename,
function (err, data)
{
if (err)
{
res.writeHead(500);
return res.end('Error loading index.html');
}
log(data);
log(filename + " has read");
res.setHeader('content-type', mime.lookup(filename));
res.writeHead(200);
res.end(data);
});
}
Your handler is hardcoded to always return the content of /index.html. You need to pay attention to the resource that is being requested and return the right one. (i.e. if the browser asks for simple.js then you need to give it simple.js instead of index.html).
function contentType(ext) {
var ct;
switch (ext) {
case '.html':
ct = 'text/html';
break;
case '.css':
ct = 'text/css';
break;
case '.js':
ct = 'text/javascript';
break;
default:
ct = 'text/plain';
break;
}
return {'Content-Type': ct};
}
var PATH = 'C:/Users/DELL P26E/node_modules'
var http = require("http");
var fs = require('fs');
var url = require("url");
var path = require("path")
var fileName = "D:/index.html";
var server = http.createServer (function (request, response) {
var dir = "D:/";
var uri = url.parse(request.url).pathname;
if (uri == "/") {
uri = "index.html";
}
var filename = path.join(dir, uri);
fs.readFile(filename,
function (err, data) {
if (err) {
response.writeHead(500);
return response.end('Error loading index.html');
}
var ext = path.extname(filename)
response.setHeader('content-type',contentType(ext));
response.writeHead(200);
response.end(data);
});
}).listen(3000);
console.log('Server running on 8124') ;
Right now I'm using this script in PHP. I pass it the image and size (large/medium/small) and if it's on my server it returns the link, otherwise it copies it from a remote server then returns the local link.
function getImage ($img, $size) {
if (#filesize("./images/".$size."/".$img.".jpg")) {
return './images/'.$size.'/'.$img.'.jpg';
} else {
copy('http://www.othersite.com/images/'.$size.'/'.$img.'.jpg', './images/'.$size.'/'.$img.'.jpg');
return './images/'.$size.'/'.$img.'.jpg';
}
}
It works fine, but I'm trying to do the same thing in Node.js and I can't seem to figure it out. The filesystem seems to be unable to interact with any remote servers so I'm wondering if I'm just messing something up, or if it can't be done natively and a module will be required.
Anyone know of a way in Node.js?
You should check out http.Client and http.ClientResponse. Using those you can make a request to the remote server and write out the response to a local file using fs.WriteStream.
Something like this:
var http = require('http');
var fs = require('fs');
var google = http.createClient(80, 'www.google.com');
var request = google.request('GET', '/',
{'host': 'www.google.com'});
request.end();
out = fs.createWriteStream('out');
request.on('response', function (response) {
response.setEncoding('utf8');
response.on('data', function (chunk) {
out.write(chunk);
});
});
I haven't tested that, and I'm not sure it'll work out of the box. But I hope it'll guide you to what you need.
To give a more updated version (as the most recent answer is 4 years old, and http.createClient is now deprecated), here is a solution using the request method:
var fs = require('fs');
var request = require('request');
function getImage (img, size, filesize) {
var imgPath = size + '/' + img + '.jpg';
if (filesize) {
return './images/' + imgPath;
} else {
request('http://www.othersite.com/images/' + imgPath).pipe(fs.createWriteStream('./images/' + imgPath))
return './images/' + imgPath;
}
}
If you can't use remote user's password for some reasons and need to use the identity key (RSA) for authentication, then programmatically executing the scp with child_process is good to go
const { exec } = require('child_process');
exec(`scp -i /path/to/key username#example.com:/remote/path/to/file /local/path`,
(error, stdout, stderr) => {
if (error) {
console.log(`There was an error ${error}`);
}
console.log(`The stdout is ${stdout}`);
console.log(`The stderr is ${stderr}`);
});