6

完成的家庭作业:

节点入门书

我如何开始使用 Node.js [关闭]

在 Node 中构建处理程序

背景故事:我想尝试编写自己的框架,但遇到了一些麻烦,很可能是因为没有完全理解它。

我想要实现的是如下所示的语法:

var app = require('./app'); //this part is understood and it works in my current code.
app.get('/someUrl', function(){ //do stuff here });
app.post('/someOtherUrl', function(){ //do stuff here });

我知道 Express 框架具有相同的语法,但阅读它们的源代码仍然让我难以理解。

这可能是一项微不足道的任务,但我根本无法制作它。

试图require('./app');在应用程序更深的文件中生成一个未定义的对象,所以我猜测服务器是一个单例对象。

那么我尝试了什么?

我当前的代码看起来像这样,不知何故我觉得这是要走的路,但我显然不能这样做。

我省略了所有require();语句以使其更具可读性。

server.js:

var app = module.exports = {
    preProcess: function onRequest(request, response){
        processor.preRequest(request); //this object adds methods on the request object
        var path = urllib.parse(request.url).pathname;
        router.route(urls, path, request, response);
    },
    createServer: function() {
        console.log("Server start up done.");
        return this.server = http.createServer(this.preProcess);
    }
};

exports.app = app;

在撰写本文时,我正在尝试用一种get()方法扩展这个对象。

index.js:

var app = require('./server');
app.createServer().listen('1337');

router.route()位基本上将请求向前发送到应用程序和 router.js 文件中,我做了一些魔术并将请求向前路由到映射(到目前为止)到 /urlThatWasRequested 的函数

这是我想留下的行为。我知道这可能是一个很高的要求,但我的所有代码都很容易丢弃,而且我不害怕重写整个代码库,因为这是我自己的项目。

我希望这足以解释我的问题,否则请说出我应该添加的内容以使这一点更清楚。

提前致谢!

4

1 回答 1

11

我不确定你的问题是什么,但这里有一些想法:

1)您在此处创建循环引用:

var app = module.exports = {
    // some other code
}
exports.app = app;

您添加appapp. 不需要最后一行。

2)您需要将处理程序保存在app. 你可以尝试这样的事情:

var app = module.exports = {
    handlers : [],
    route : function(url, fn) {
        this.handlers.push({ url: url, fn: fn });
    },
    preProcess: function onRequest(request, response){
        processor.preRequest(request);
        var path = urllib.parse(request.url).pathname;
        var l = this.handlers.length, handler;
        for (var i = 0; i < l; i++) {
            handler = this.handlers[i];
            if (handler.url == path)
                return handler.fn(request, response);
        }
        throw new Error('404 - route does not exist!');
    },
    // some other code
}

请注意,您可以更改此行:以正则表达式if (handler.url == path)的方式进行测试。当然,您可以实现和变体,但根据我的经验,检查请求是否在处理程序中或处理程序内部更容易。现在您可以像这样使用上面的代码:handler.urlpath.get.postGETPOST

app.route('/someUrl', function(req, res){ //do stuff here });

另一件事是我向您展示的代码只触发它匹配的给定 URL的第一个处理程序。您可能想要制作涉及许多处理程序(即中间件)的更复杂的路由。在这种情况下,架构会有所不同,例如:

preProcess: function onRequest(request, response){
    var self = this;
    processor.preRequest(request);
    var path = urllib.parse(request.url).pathname;
    var l = self.handlers.length,
        index = 0,
        handler;
    var call_handler = function() {
        var matched_handler;
        while (index < l) {
            handler = self.handlers[index];
            if (handler.url == path) {
                matched_handler = handler;
                break;
            }
            index++;
        }
        if (matched_handler)
             matched_handler.fn(request, response, function() {
                 // Use process.nextTick to make it a bit more scalable.
                 process.nextTick(call_handler);
             });
        else
             throw new Error('404: no route matching URL!');
     };
     call_handler();
},

现在在您的路线内,您可以使用

app.route('/someUrl', function(req, res, next){ 
    //do stuff here
    next(); // <--- this will take you to the next handler
});

这会将您带到另一个处理程序(如果没有更多处理程序,则抛出异常)。

3)关于这些话:

试图要求('./app'); 在应用程序更深处的文件中会产生一个未定义的对象,所以我猜测服务器是一个单例对象。

这不是真的。require总是返回对模块对象的引用。如果你看到undefined,那么你搞砸了其他东西(改变了模块本身?)。

最后说明:我希望它有所帮助。编写自己的框架可能是一项艰巨的工作,特别是因为已经有像 Express 这样的优秀框架。不过祝你好运!

编辑

实现.get.set方法其实并不难。你只需要改变route这样的功能:

route : function(url, fn, type) {
    this.handlers.push({ url: url, fn: fn, type: type });
},
get : function(url, fn) {
    this.route(url, fn, 'GET');
},
post : function(url, fn) {
    this.route(url, fn, 'POST');
},

然后在路由算法中检查是否type定义了属性。如果不是,则使用该路由(undefined类型表示:始终路由)。否则另外检查请求的方法是否匹配类型。你完成了!

于 2012-07-11T08:57:22.620 回答