0

我正在尝试按照 Adam Freeman 的 Apress“Pro JavaScript for Web Apps”中的建议设置 Node。我已经在我的 Mac (OS 10.6.8) 机器上安装了 Node (0.10.7) 并运行了各种示例来证明 Node 正在工作,例如

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/');

所以我可以从终端启动 Node,然后在浏览器中获得“Hello World”。到目前为止一切似乎都很好。

然后我发出命令来添加本书建议的某些包:

npm install node-static jqtpl

这也有效;它通过 HTTP GET 命令获取了一堆东西,并且似乎安装它们没有错误。

Adam 的示例文件有两个组成部分:有一个“server.js”文件,还有一个包含每章示例的“content”目录。我的问题似乎与文件和内容目录之间的路径有关,或者基于谷歌搜索此 EACCESS 错误,某些权限问题。我尝试了各种配置(将 server.js 放在我的“dave”目录中,这是我在 Mac 上的用户目录,并将“content”目录作为“dave”的子目录;这似乎是他想要的根据书中的说明;或者,将 server.js 放在内容目录中;由于路径错误,这似乎不起作用。

无论如何,当我将“server.js”放在“dave”目录中,并让“content”也存在于“dave”目录中时(实际上,对于 server.js 所在目录中的任何目录来说,这似乎都是正确的,和内容也驻留在同一个目录中),我得到这个:

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)

警告:我几乎是 Unix 新手(我是 .Net 开发人员),所以可能只是我不了解 Unix 权限、路径或 PATH 变量。Adam 谈到将东西放在“你的 Node.js 目录中”,我认为这可能不够具体。我对本地机器上的行为的观察是 NODE 可执行文件显然在我的 PATH 中,因为我可以从我的用户目录执行上述命令。无论如何,我怀疑这是一些权限问题。

为了完整起见,这里是亚当的代码:

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;
}
4

2 回答 2

6

Unix 要求进程运行root以侦听小于 1024 的网络端口。将程序中的端口更改为更高的端口,例如 3000。

于 2013-05-26T07:34:27.000 回答
0

我在 Win 7 中通过 Adam Freeman 的“Pro Javascript for Web Apps”设置过程遇到了同样的问题。

解决方案是相同的 - 从 server.js 文件中的端口 80 更改:

例如

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

工作得很好。

于 2014-02-27T08:46:21.343 回答