David Barrows David Barrows - 2 months ago 10
Node.js Question

Node JS EACCESS error (Pro JS for Web Apps book) - path or permissions?

I'm trying to set up Node as per the suggestions in the Apress "Pro JavaScript for Web Apps" by Adam Freeman. I've installed Node (0.10.7) on my Mac (OS 10.6.8) machine and run various examples proving Node is working, such as

var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');


so I can launch Node from the Terminal, then get a "Hello World" in the browser. All seems well so far.

Then I issue the command to add certain packages suggested by the book:

npm install node-static jqtpl


and that also works; it gets a bunch of stuff via HTTP GET commands and seems to install them without error.

Adam's example files have two components: there's a "server.js" file, and there's a "content" directory containing examples from each chapter. My problem seems to have to do with either the path between the file and the content directory, or, based on googling this EACCESS error, some permissions issue. I've tried various configurations (putting server.js in my "dave" directory, which is my user directory on the Mac, and also putting the "content" directory as a subdirectory of "dave"; that seems to be what he wants from the instructions in the book; or, putting server.js IN the content directory; that seems to not work because of a path error.

In any case when I put "server.js" in the "dave" directory, and let "content" exist also in the "dave" directory (actually this seems to be true for any directory where server.js resides in the directory, and content also resides in that same directory), I get this:

dave$ node server.js
Ready on port 80

events.js:72
throw er; // Unhandled 'error' event
^
Error: listen EACCES
at errnoException (net.js:884:11)
at Server._listen2 (net.js:1003:19)
at listen (net.js:1044:10)
at Server.listen (net.js:1110:5)
at Object.<anonymous> (/Users/dave/NodeJsTesting/server.js:92:34)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)


Caveats: I'm pretty much a Unix newbie (I'm a .Net dev), so it could just be there's something I don't understand about Unix permissions, paths, or the PATH variable. Adam talks about putting stuff "in your Node.js directory" which I think is perhaps not specific enough. My observation about the behavior on my local machine is that the NODE executable is obviously in my PATH, because I can execute the above commands from my user directory. Anyway I suspect this is some permissions issue.

In the interest of completeness, here's Adam's code:

var http = require('http');
var url = require('url');
var fs = require('fs');
var nodestatic = require('node-static');
var jqtpl = require("jqtpl");
var querystring = require('querystring');

var fileserver = new(nodestatic.Server)("./content", { cache: 1 });
var productData = JSON.parse(fs.readFileSync("./content/products.json"));

function handleRequest(req, res) {
console.log(req.method + " request for " + req.url);

if (req.method == "POST") {
var fullBody = '';
req.on('data', function(chunk) {fullBody += chunk.toString();});
req.on('end', function() {
var data = createDataObject(querystring.parse(fullBody));

if (req.headers['x-http-method-override']) {
var productID = req.url.split("/").pop();

switch (req.headers['x-http-method-override']) {
case "delete":
data.deleteItem(productID);
break;
case "put":
var item = data.getItem(productID);
if (item) {
item.name = data.getAndRemoveDataProp("name");
item.price = data.getAndRemoveDataProp("price")
}
break;
}
writeJSONData(res, productData);
} else {
switch (req.url) {
case "/formecho":
case "/basket":
case "/basket":
case "/shipping":
case "/summary":
res.write(jqtpl.tmpl(loadTemplate(req.url.substring(1)), data));
break;
}
res.end();
}
});

} else {

if (req.url.indexOf("/shortJSONP") == 0) {
var callback = querystring.parse(url.parse(req.url).query)["callback"];
res.setHeader("Content-Type", "text/javascript");
res.write(callback + "(" + JSON.stringify([productData[0]]) + ")");
res.end();

} else {

if (req.headers["origin"] && req.headers["origin"].indexOf("cheeselux") > -1) {
res.setHeader("Access-Control-Allow-Origin", req.headers["origin"]);
}

switch (req.url) {

case "/cheeselux.appcache":
fileserver.serveFile("cheeselux.appcache", 200,
{"Content-Type": "text/cache-manifest"}, req, res);
break;
case "/products.json.slow":
setTimeout(function() {
fileserver.serveFile("products.json", 200, null, req, res);
}, 1000);
break;
case "/shortJSONList":
writeJSONData(res, [productData[0]]);
break;
case "/admin/products":
writeJSONData(res, productData);
break;
default:
if (req.url == "/") {
req.url = "/example.html";
}
fileserver.serve(req, res);
break;
};
}
}
}

http.createServer(handleRequest).listen(80);
console.log("Ready on port 80");

function loadTemplate(name) {
return fs.readFileSync("content/" + name + ".html").toString();
}

function writeJSONData(res, data) {
res.setHeader("Content-Type", "application/json");
res.write(JSON.stringify(data));
res.end();
}

function createDataObject(reqData) {
var data = {
properties: [],

getItem: function(id) {
for (var i = 0; i < productData.length; i++) {
for (var j = 0; j < productData[i].items.length; j++) {
if (productData[i].items[j].id == id) {
return productData[i].items[j];
}
}
}
return null;
},

deleteItem: function(id) {
for (var i = 0; i < productData.length; i++) {
for (var j = 0; j < productData[i].items.length; j++) {
if (productData[i].items[j].id == id) {
productData[i].items.splice(j, 1);
}
}
}
},

getProp: function (id, prop) {
for (var i = 0; i < productData.length; i++) {
for (var j = 0; j < productData[i].items.length; j++) {
if (productData[i].items[j].id == id) {
return productData[i].items[j][prop];
}
}
}
return "";
},

getAndRemoveDataProp: function(prop) {
for (var i = 0; i < this.properties.length; i++) {
if (this.properties[i].propName == prop) {
var result = this.properties[i].propVal;
this.properties.splice(i, 1);
return result;
}
}
return "";
},

total: 0,
getSubtotal: function(id, quantity) {
var price = this.getProp(id, "price") * quantity;
this.total += price;
return price;
}
}

for (var prop in reqData) {
data.properties.push({propName: prop, propVal: reqData[prop]})
}
return data;
}

Answer

Unix requires the process to be running as root to listen on network ports less than 1024. Change the port in your program to a higher port like 3000.