I am trying to set up a basic node.js server and am getting an error I cannot figure out. I have 4 files: index.js, server.js, router.js, requestHandlers.js
index.js
var server = require("./server");
var router = require("./router");
var requestHandlers = ("./requestHandlers");
var handle = {}
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
server.start(router.route, handle);
server.js
var http = require('http');
var url = require("url");
function start(route, handle) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received"); // 2nd log-- works fine
route(handle, pathname);
response.writeHead(200, {'Content-Type': 'text/plain'});
response.write('Hello World');
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started."); //1st log -- works fine
};
exports.start = start;
router.js
function route(handle, pathname) {
console.log("About to route a request for " + pathname); //3rd log -- works fine
console.log(handle); // THIS IS THE PROBLEM returns ---> { '/': undefined, '/start': undefined, '/upload': undefined }
console.log(pathname); //works fine -- returns "/"
console.log(typeof handle[pathname]); //undefined
if (typeof handle[pathname] === 'function') {
handle[pathname](); //never called because above evaluates to undefined
}
else {
console.log("No request handler found for " + pathname);
}
}
exports.route = route;
requestHandlers.js //code never gets here
function start () {
console.log("Request handler 'start' was called")
}
function upload () {
console.log("Request handler 'upload' was called")
}
exports.start = start;
exports.upload = upload;
I have gone over this 100 times and feel pretty confident about what it's doing, so hopefully there is just some small thing I am missing. thanks!
I think you accidentally forgot the verb (require).
var requestHandlers = require("./requestHandlers");
Related
i am taking first steps in node.js and came across an issue when trying to rout request my server receives.
i have the following files in my project, all in the same level of hierarchy:
server.js:
var http = require('http');
var url = require('url');
function start(route,handle){
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received");
route(handle,pathname);
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.")
}
exports.start = start;
requestHandlers.js:
function start(){
console.log("Request handler 'start' was called");
}
function upload(){
console.log("Request handler 'upload' was called");
}
exports.start = start;
exports.upload = upload;
router.js:
function route(handle,pathname){
console.log("About to route a request for" + pathname );
if (typeof handle[pathname] === 'function'){
handle[pathname];
} else {
console.log('No request handler found for' + pathname);
}
}
exports.route = route;
and the last one is index.js:
var server = require('./server');
var router = require('./router');
var requestHandlers = require('./requestHandlers');
var handle = {};
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
server.start(router.route,handle);
when i type in my browser the URL "localhot:8888/start" for example, i get this in the console:
Server has started.
Request for /upload received
About to route a request for/upload
Request for /favicon.ico received
About to route a request for/favicon.ico
No request handler found for/favicon.ico
but why want i see the console.log i expected to see from the upload() or start()functions?
thx!
It could be because you never invoke your start or upload functions. Try adding some parentheses after handle[pathname] in router.js like this:
function route(handle,pathname){
console.log("About to route a request for" + pathname );
if (typeof handle[pathname] === 'function'){
handle[pathname]();
} else {
console.log('No request handler found for' + pathname);
}
}
exports.route = route;
Hope this helps.
I am working on a Team Treehouse project that builds a dynamic website with Node.js. The user enters in a username into the search field and it displays the user's avatar, number of badges earned and the number of JavaScript points. For some reason when I enter in the user name and click search the page just goes blank. I think there might be something wrong with the 303 redirection in my router.js file. I'm still fairly new to coding so any insight would be very helpful. Here are each of my js files.
/*****app.js file******/
var router = require('./router.js');
//Problem: We need a simple way to look at a user's badge count and JavaScript points from a web browser
//Solution: Use Node.js to perform the profile look ups and serve our templates via HTTP
//Create a web server
var http = require('http');
http.createServer(function (request, response) {
router.home(request, response);
router.user(request, response);
}).listen(3000);
console.log('Server running at http://<workspace-url>');
/*****router.js file******/
var Profile = require("./profile.js");
var renderer = require('./renderer');
var querystring = require('querystring');
var commonHeader = {'Content-Type': 'text/html'};
// Handle the HTTP route GET / and POST / i.e. Home
function home(request, response) {
//if url == "/" && GET
if (request.url === '/'){
if (request.method.toLowerCase() === "get") {
//show search
console.log(request.url);
response.writeHead(200, commonHeader);
renderer.view('header', {}, response);
renderer.view('search', {}, response);
renderer.view('footer', {}, response);
response.end();
}
else {
//if url == "/" && POST
//get the post data from body
request.on('data', function(postBody){
//extract the username
var query = querystring.parse(postBody.toString());
//redirect to /:username
response.writeHead(303, {'Location': '/' + query.username });
response.end();
});
}
}
}
// Handle the HTTP route for GET /:username i.e. /chalkers
function user(request, response) {
//if url == "/...."
var username = request.url.replace('/', '');
if(user.name.length > 0){
response.writeHead(200, commonHeader);
renderer.view('header', {}, response);
//get json from Treehouse
var studentProfile = new Profile(username);
//on "end"
studentProfile.on("end", function(profileJSON){
//show profile
//Store the values which we need
var values = {
avatarUrl: profileJSON.gravatar_url,
username: profileJSON.profile_name,
badges: profileJSON.badges.length,
javascriptPoints: profileJSON.points.JavaScript
}
//Simple response
renderer.view('profile', values, response);
renderer.view('footer', {}, response);
response.end();
});
//on "error"
studentProfile.on("error", function(error){
//show error
renderer.view('error', {errorMessage: error.message}, response);
renderer.view('search', {}, response);
renderer.view('footer', {}, response);
response.end();
});
}
}
module.exports.home = home;
module.exports.user = user;
/*****profile.js file*******/
var EventEmitter = require("events").EventEmitter;
var http = require("http");
var util = require("util");
/**
* An EventEmitter to get a Treehouse students profile.
* #param username
* #constructor
*/
function Profile(username) {
EventEmitter.call(this);
profileEmitter = this;
//Connect to the API URL (http://teamtreehouse.com/username.json)
var request = http.get("http://teamtreehouse.com/" + username + ".json", function(response) {
var body = "";
if (response.statusCode !== 200) {
request.abort();
//Status Code Error
profileEmitter.emit("error", new Error("There was an error getting the profile for " + username + ". (" + http.STATUS_CODES[response.statusCode] + ")"));
}
//Read the data
response.on('data', function (chunk) {
body += chunk;
profileEmitter.emit("data", chunk);
});
response.on('end', function () {
if(response.statusCode === 200) {
try {
//Parse the data
var profile = JSON.parse(body);
profileEmitter.emit("end", profile);
} catch (error) {
profileEmitter.emit("error", error);
}
}
}).on("error", function(error){
profileEmitter.emit("error", error);
});
});
}
util.inherits( Profile, EventEmitter );
module.exports = Profile;
/*****renderer.js file*******/
var fs = require('fs');
function mergeValues(values, content) {
//Cycle over the keys
for(var key in values) {
//Replace all the {{key}} with the value from the values object
content = content.replace('{{' + key + '}}', values[key]);
}
//return merged content
return content;
}
function view(templateName, values, response) {
//Read from the template file
var fileContents = fs.readFileSync('./views/' + templateName + '.html', {encoding: 'utf8'});
//Insert values in to the content
fileContents = mergeValues(values, fileContents);
//Write out the contents to the response
response.write(fileContents);
}
module.exports.view = view;
Treehouse changed from http to https and so this example code doesn't work any longer. The reason for that is in the profile.js file. You are making calls for an http site and it doesn't exist. You need to change the code (only in profile.js) to make it connect to the https site instead.
var http = require("http");
should be changed to
var https = require("https");
and with that all references to the variable in your profile.js code should be changed to https.
As well as the hard-coded URL start:
var request = http.get("http://teamtreehous...
should be
var request = https.get("https://teamtreehous...
That should resolve the problem. Good luck!
In order to get your code in the profile.js file to run, you need to change some instances of the "http" module to "https" but, and this is important, not all instances.
What needs to remain http is the the status code error on the profile.js page. This line of code is correct:
profileEmitter.emit("error", new Error("There was an error getting the profile for " + username + ". (" + http.STATUS_CODES[response.statusCode] + ")"));
But all other instances of the http module need to change to https. For example, these lines are correct:
var url = "https://teamtreehouse.com/" + username + ".json";
var request = https.get(url, function(response){
Remember to require both modules at the top of profile.js page
var http = require("http");
var https = require("https");
I'm trying to use node.js as webserver, my source is divided into four modules.
index.js
server.js
router.js
requestHandlers.js
The aim of the code is to show in /, /start and /upload different pages, while if I type another path I should get Error 404. However I get error as soon as I send the request to the server.
This is my error:
> Server has started. Request for /start received. About to route a
> request for /start Request handler 'start' was called.
>
> http.js:852
> throw new TypeError('first argument must be a string or Buffer');
> ^ TypeError: first argument must be a string or Buffer
> at ServerResponse.OutgoingMessage.write (http.js:852:11)
> at Server.onRequest (/Users/Alessio/Desktop/Circolare/server.js:12:14)
> at Server.emit (events.js:98:17)
> at HTTPParser.parser.onIncoming (http.js:2113:12)
> at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:122:23)
> at Socket.socket.ondata (http.js:1971:22)
> at TCP.onread (net.js:528:27)
index.js
var server = require("./server");
var router = require("./router");
var requestHandlers=require("./requestHandlers");
var handle={}
handle["/"]=requestHandlers.start;
handle["/start"]=requestHandlers.start;
handle["/upload"]=requestHandlers.upload;
server.start(router.route, handle);
server.js here is where I have the error
var http = require("http");
var url = require("url");
function start(route, handle) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
response.writeHead(200, {"Content-Type": "text/plain"});
var content = route(handle, pathname); //Here the ERROR
response.write(content);
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
router.js
function route(handle, pathname){
console.log("About to route a request for " + pathname);
if(typeof handle[pathname] === 'function'){
handle[pathname]();
}
else{
console.log("No request handler found for " + pathname);
return "404 Not Found";
}
}
exports.route = route;
requestHandlers.js
function start(){
console.log("Request handler 'start' was called.");
return "Hello Start";
}
function upload(){
console.log("Request handler 'upload' was called.");
return "Hello Upload";
}
exports.start=start;
exports.upload=upload;
Looks like you don't return anything from your route() function on success:
function route(handle, pathname){
console.log("About to route a request for " + pathname);
if(typeof handle[pathname] === 'function'){
return handle[pathname](); // <-- probably need a `return` statement here...
}
else{
console.log("No request handler found for " + pathname);
return "404 Not Found";
}
}
You could update the route function by adding a return to the function call handlepathname,it should work then.
function route(handle, pathname){
console.log("About to route a request for " + pathname);
if(typeof handle[pathname] === 'function'){
return handle[pathname]();
}
else{
console.log("No request handler found for " + pathname);
return "404 Not Found";
}
}
exports.route = route;
It seems like the data event on the request object is not firing, or I can't wire it up right in order to get anything from it. I am getting the end event just fine, and all the urls are working. I have looked on forums and documentation, and when I look at my code it seems like it should work. I am using Node version 0.10.12.
I am new. I am trying to get a simple server going in node. I was following The Node Beginner Book. Most of this code comes from there, with some very small modifications. I have already tried the code straight from the book.
Here is the code I am working with now.
index.js
var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");
var handle = {};
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
if (process.argv[2] !== undefined && process.argv[2] !== null) {
server.start(router.route, handle, process.argv[2]);
} else {
server.start(router.route, handle);
}
router.js
route = function(handle, pathname, response, postData) {
if (typeof handle[pathname] === "function") {
handle[pathname](response, postData);
} else {
response.writeHead(404, {"Content-Type": "text/plain"});
response.end("404 Not found");
}
}
exports.route = route;
server.js
var http = require('http');
var url = require('url');
var portToUse = 8888;
start = function(route, handle, port) {
if (port !== undefined && port !== null && typeof parseInt(port) === 'number' && port > 1000 && port < 10000) {
console.log('You passed in the port number %d.', port);
portToUse = port;
}
http.createServer(function(request, response) {
var postData = '';
var pathname = url.parse(request.url).pathname;
console.log('Request for %s received.', pathname);
route(handle, pathname, response);
request.setEncoding('utf8');
// I have tried both .on and .addListener
request.on('data', function(postDataChunk) {
postData += postDataChunk;
console.log('Received POST data chunk %s.', postData);
});
request.on('end', function(postDataChunk) {
console.log(postDataChunk);
route(handle, pathname, response, postData);
});
}).listen(portToUse);
console.log('The server listening on %d.', portToUse);
}
exports.start = start;
requestHandlers.js
var exec = require('child_process').exec;
start = function(response, postData) {
var body = '<!doctype html>' +
'<html lang="en">' +
'<head>' +
'<meta charset="UTF-8">' +
'<title>Upload Server</title>' +
'</head>' +
'<body>' +
'<form action="/upload">' +
'<textarea name="text" id="text-area" cols="40" rows="20"></textarea>' +
'<input type="submit" value="Submit text">' +
'</form>' +
'</body>' +
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.end(body);
}
upload = function(response, postData) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('You\'ve sent: ' + postData);
}
exports.start = start;
exports.upload = upload;
Thanks in advance.
You need to add your data listener before you call route. Reason being, in your handlers you are calling response.end. When you do this, node checks if there are any data listeners on the socket, and if not, it will dump the existing request data, as it figures it's no longer needed.
I have a file called node.js:
var net = require('net');
var crypto = require('crypto');
//sjcl
var sjcl = require('./sjcl');
//retrive fb profile
var loadFb = require('./loadFb.js');
var loadFeed = require('./loadFeed.js');
//read json user file
var fs = require('fs');
var text = fs.readFileSync(__dirname + '/users','utf8');
var HOST = 'localhost';
var PORT = 7000;
net.createServer(function(sock) {
// We have a connection - a socket object
console.log('CONNECTED: ' + sock.remoteAddress +':'+ sock.remotePort);
// Add a 'data' event handler to this instance of socket
sock.on('data', function(data) {
console.log('User request profile of: ' + data);
//var date = (data.toString()).split("***");
//var from = date[1];
loadFb(extendetPath, function(pageData)
{
loadFeed(extendetPath2, function(pageData2)
{
var fs = require('fs');
var profileText = fs.readFileSync('/tmp/profile','utf8');
console.log(profileText);
sock.write(profileText);
});
});
});
// Add a 'close' event handler to this instance of socket
sock.on('close', function(data) {
console.log('CLOSED: ' + sock.remoteAddress +' '+ sock.remotePort);
});
}).listen(PORT);
console.log('Server listening on ' + HOST +':'+ PORT);
function returnKeyFromUser(id)
{
//text
var trovata = false;
var dati = JSON.parse(text);
for(var i=0; i<dati.friendlist.friend.length && trovata==false; i++)
{
var user = (dati.friendlist.friend[i].username).replace("\n","");
var userID = (id).replace("\n","");
if(user==userID)
{
trovata=true;
return ((dati.friendlist.friend[i].publicKey).toString()).replace("\n","");
}
}
if(trovata==false)
return null;
}
There is a small http server that receives a facebook username and what he have to do is retrieve 2 page:
a graphapi with the profile information, and a graphapi with the feed informations of a facebook profile
I copy the other two files:
var https = require('https');
module.exports = function(path, callback) {
var options = {
host: 'graph.facebook.com',
port: 443,
path: (path.toString()).replace("\n",""),
method: 'GET'
};
var req = https.get(options, function(res) {
var pageData = "";
if((path.toString()).indexOf("/")==0 && (path.toString()).indexOf("/GET /`HTTP/")!=0)
//for load only (I hope facebook profile)
{
console.log(options);
res.setEncoding('utf8');
res.on('data', function (chunk) {
pageData += chunk;
});
res.on('end', function()
{
var fs = require('fs');
fs.writeFile("/tmp/profile", pageData, function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});
//callback(pageData);
return;
});
}
});
};
3° file
var https = require('https');
module.exports = function(path, callback) {
var options = {
host: 'graph.facebook.com',
port: 443,
path: (path.toString()).replace("\n",""),
method: 'GET'
};
var req = https.get(options, function(res) {
var pageData = "";
if((path.toString()).indexOf("/")==0 && (path.toString()).indexOf("/GET / HTTP/")!=0) //for load only (I hope facebook profile)
{
console.log(options);
res.setEncoding('utf8');
res.on('data', function (chunk) {
pageData += chunk;
});
res.on('end', function()
{
var fs = require('fs');
fs.appendFile('/tmp/profile', "***"+pageData, function (err) {
if (err) throw err;
console.log('It\'s saved!');
});
callback(pageData);
});
}
});
};
I don't know If there is a way to call the two file in the first file node.js but what I done is this: (to call from node.js the fist file, and from the second file call the third)
in node.js file I call the first file loadFb.js with this command:
loadFb(extendetPath, function(pageData)
{
This call saves a file on my tmp profile directory and inside I call the other file loadFeed that appends some text.
After that I have to send the entire information to the client but I have a mistake.
In order the nodejs correctly call loadFb and he write tmp - profile, than he call loadFeed
but before appending the information the node call back to the client only the half of informations that I need.
I'm not a good nodejs programmer, this is a work for my thesis.
Can someone help me?
Let's look at the following code:
res.on('end', function()
{
var fs = require('fs');
fs.appendFile('/tmp/profile', "***"+pageData, function (err) {
if (err) throw err;
console.log('It\'s saved!');
});
callback(pageData);
});
What it does it runs the asynchronous method appendFile and immediately after that calls callback. So when the code in the callback is executed, the file is not updated yet. You need to move the callback(pageData); to the appendFile's callback. And you need to review you code keeping this in mind because I see that the same fix should be made in another file so maybe there are some similar places as well.