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.
Related
I am trying to create an HTTP server that the user can upload images and archives, and for that I am using formidable for handling the upload part.
My code :
requestHandler.js
// Request Handlers (will handle all requests that happen)
// Allows Node.js to make use of a non-blocking operation: exec ();
var exec = require("child_process").exec;
var querystring = require("querystring");
fs = require("fs");
var fomidable = require("formidable");
function start(response, postData) {
console.log("Request handler 'start' was called");
var body = '<html>' +
'<head>' +
'<meta http-equiv = "Content-Type" content = "text/html";'+
'charset="UTF-8"/>' +
'</head>' +
'<body>' +
'<form action = "/upload" enctype = "multipart/form-data"' +
'method = "post">' +
'<input type ="file" name = "upload multiple = "multiple">' +
'<input type = "submit" value ="Upload file" />' +
'</form>' +
'</body>' +
'</html>';
response.writeHead(200, {"Content-Type" : "text/html"});
response.write(body);
response.end();
}
// What is being passed between router.js and requestHandler.js is the entire body of the POST data request.
function upload(response, request) {
console.log("Request handler 'upload' was called");
var form = new formidable.IncomingForm();
console.log("about to parse");
form.parse(request, function(error, fields, files) {
console.log("parsing done");
/*Possible error on Windows systems; tried to rename to an already existing file*/
fs.rename(files.upload.path, "/tmp/test.png", function(err) {
if(err) {
fs.unlink("/tmp/test.png");
fs.rename(files.upload.path, "/tmp/test.png");
}
});
response.writeHead(200, {"Content-Type" : "text/plain"});
response.write("You've sent the text : " + querystring.parse(postData).text);
response.write("\nHello Upload");
response.end();
});
}
function show(response) {
console.log("Request handler 'show' was called.");
fs.readFile("/tmp/test.png", "binary", function(error,file) {
if(error) {
response.writeHead(500, {"Content-Type" : "text/plain"});
response.write(err + "\n");
response.end();
} else {
response.writeHead(200, {"Content-Type" : "image/png"});
response.write(file, "binary");
reponse.end();
}
});
}
exports.start = start;
exports.upload = upload;
exports.show = show;
I am using too formidable in the another part of my code, in my server.js but there for some reason works (And for that reason I am not posting the code), the error point out to requestHandler.js in line 35 :
var form = new formidable.IncomingForm();
formidable is not defined
How can I make formidable defined ? When I am already doing that calling in the first place in :
var formidable = require("formidable");
I think you have a typo...
var fomidable = require("formidable");
Should probably be:
var formidable = require("formidable");
Hence the formidable is not defined... you defined it as fomidable.
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 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");
I have written a http server using node js
var sys = require("sys"),
http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs");
http.createServer(function(request, res) {
var parsed_url = url.parse(request.url);
var uri = parsed_url.pathname;
if(uri === "/test"){
res.writeHead(200, {'Content-Type': 'text/javascript'});
request.addListener('data', function (chunk) {
var data = eval("(" + chunk + ")");
console.log(data[0].id);
})
request.addListener('end', function() {
console.log('end triggered');
res.write("Post data");
res.end();
});
}
}).listen(8080);
and i am trying to send back response of ajax request but i am unable to receive any response. Here is the code for ajax request ,
var myhttp = new XMLHttpRequest();
var url = "http://localhost:8080/test";
var data = [{"a":"1"},{"b":"2"},{"c":"3"}];
var dataJson = JSON.stringify(data);
myhttp.open('POST', url, true);
myhttp.send(dataJson);
myhttp.onreadystatechange = function() {
if ((myhttp.readyState == 4) && (myhttp.status == 200)){
alert(myhttp.responseText);
}
else if ((myhttp.readyState == 4) && (myhttp.status != 200))
{
console.log("Error in Connection");
}
Can anyone help me what i am doing wrong ...
Thanks
Vinay
Your code is almost right but on your code sample you have
console.log(data[0].id)
the data object has no property id so if you only have
console.log(data[0])
there you have a response like
{ a: '1' }
therefore you can access the property a by doing
console.log(data[0].a);
UPDATED Updated with a full example
One more thing is that you are using eval and node comes with JSON.parse bundle with it so the snippet below is how i made it work
File: app.js
var sys = require("sys"),
http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs");
http.createServer(function(request, res) {
var parsed_url = url.parse(request.url);
var uri = parsed_url.pathname;
if(uri === "/test"){
res.writeHead(200, {'Content-Type': 'text/javascript'});
request.addListener('data', function (chunk) {
// removed this - eval("(" + chunk + ")");
var data = JSON.parse(chunk);
console.log(data[0].a);
})
request.addListener('end', function() {
console.log('end triggered');
res.write("Post data");
res.end();
});
} else if(uri === "/") {
fs.readFile("./index.html",function(err, data){
if(err) throw err;
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(data);
});
}
}).listen(8080);
On the same directory create a file index.html with the following:
<html>
<head>
<script type="text/javascript" charset="utf-8">
var myhttp = new XMLHttpRequest();
var url = "http://localhost:8080/test";
var data = [{"a":"1"},{"b":"2"},{"c":"3"}];
var dataJson = JSON.stringify(data);
myhttp.open('POST', url, true);
myhttp.send(dataJson);
myhttp.onreadystatechange = function() {
if ((myhttp.readyState == 4) && (myhttp.status == 200)){
alert(myhttp.responseText);
}
else if ((myhttp.readyState == 4) && (myhttp.status != 200))
{
console.log("Error in Connection");
}
}
</script>
</head>
<body>
</body>
</html>
That is a complete working example of what you want.
With regards to the same origin policy issues you were having is mainly due to the fact that you cant POST data between 2 different domains via ajax unless you use some tricks with iframes but that is another story.
Also i think is good for anyone to understand the backbone of a technology before moving into frameworks so fair play to you.
good luck
You have to read the data in a different way. Posted data arrives on a node server in chunks (the 'data' event), that have to be collected until the 'end' event fires. Inside this event, you are able to access your payload.
var body = '';
request.addListener('data', function (chunk) {
body += chunk;
});
request.addListener('end', function() {
console.log(body);
res.write('post data: ' + body);
});
Additionaly, there seem to be some issues with your client-side code (especially concerning the status-code checks), but i can't really help you with those as i always work with frameworks like jQuery to manage async requests.
If you want to build reliable node.js servers for web use, i highly recommend the high-performance HTTP-Framework Express. It takes away alot of the pain when developing a web-based server application in node and is maintained actively.