javascript Node.js 中的 URL 路由
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11428588/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
URL routing in Node.js
提问by Henrik Andersson
Homework done:
做的功课:
How do I get started with Node.js [closed]
Backstory: I wanted to try and write my own framework but I'm running into some troubles, most likely due to not understanding it fully.
背景故事:我想尝试编写自己的框架,但遇到了一些麻烦,很可能是因为没有完全理解它。
What I want to achieve is a syntax that looks like this:
我想要实现的是一个看起来像这样的语法:
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 });
I know of the Express-framework that has this same syntax but reading their source code still eludes me.
我知道 Express 框架具有相同的语法,但我仍然无法阅读它们的源代码。
This might be a trivial task to achieve but I simply can't produce it, yet.
这可能是一项微不足道的任务,但我根本无法完成它。
Trying to require('./app');
in a file deeper in the application produces a undefined object, so I'm guessing that a server is a singleton object.
尝试require('./app');
在应用程序更深的文件中生成一个未定义的对象,所以我猜测服务器是一个单例对象。
So what have I tried?
那么我尝试了什么?
My current code looks like this, and somehow I feel like this is the way to go, but I can't apparently do it like this.
我当前的代码看起来像这样,不知何故我觉得这是要走的路,但我显然不能这样做。
I'm omitting all the require();
statements to keep it more readable.
我省略了所有require();
语句以使其更具可读性。
server.js:
服务器.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;
At the time of writing I'm experimenting with extending this object with a get()
method.
在撰写本文时,我正在尝试用一种get()
方法扩展这个对象。
index.js:
索引.js:
var app = require('./server');
app.createServer().listen('1337');
the router.route()
bit basically sends the request onward into the application and inside the router.js-file I do some magic and route the request onward to a function that maps (so far) to the /urlThatWasRequested
该router.route()
位基本上将请求向前发送到应用程序和 router.js 文件内部我做了一些魔术并将请求向前路由到映射(到目前为止)到 /urlThatWasRequested 的函数
This is the behavior I'd like to leave behind. I know this might be a pretty tall order but all my code is easily discardable and I'm not afraid of rewriting the entire codebase as this is my own project.
这是我想留下的行为。我知道这可能是一个很高的要求,但我所有的代码都很容易丢弃,而且我不害怕重写整个代码库,因为这是我自己的项目。
I hope this is sufficient in explaining my question otherwise, please say what I should add to make this a bit more clear.
我希望这足以解释我的问题,否则请说我应该添加什么以使这更清楚。
Thanks in advance!
提前致谢!
回答by freakish
I'm not exactly sure what your question is, but here's some thoughts:
我不确定你的问题是什么,但这里有一些想法:
1)You are creating a circular reference here:
1)您在此处创建循环引用:
var app = module.exports = {
// some other code
}
exports.app = app;
You add app
as a property of app
. There's no need for the last line.
您添加app
为 的属性app
。不需要最后一行。
2)You need to hold handlers in app
. You can try something like this:
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
}
Note that you may alter this line: if (handler.url == path)
in such a way that handler.url
is a regular expression and you test path
against it. Of course you may implement .get
and .post
variants, but from my experience it is easier to check whether a request is GET
or POST
insidethe handler. Now you can use the code above like this:
请注意,您可以更改此行:if (handler.url == path)
以handler.url
正则表达式的方式并path
针对它进行测试。当然,您可以实现.get
和.post
变体,但根据我的经验,检查请求是否在处理程序中GET
或POST
在处理程序内部更容易。现在你可以像这样使用上面的代码:
app.route('/someUrl', function(req, res){ //do stuff here });
The other thing is that the code I've shown you only fires the firsthandler for a given URL it matches. You would probably want to make more complex routes involving many handlers (i.e. middlewares). The architecture would be a bit different in that case, for example:
另一件事是,我向您展示的代码仅针对它匹配的给定 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();
},
Now inside your route you can use
现在在您的路线内您可以使用
app.route('/someUrl', function(req, res, next){
//do stuff here
next(); // <--- this will take you to the next handler
});
which will take you to another handler (or throw exception if there are no more handlers).
这将带您到另一个处理程序(如果没有更多处理程序,则抛出异常)。
3)About these words:
3)关于这些话:
Trying to require('./app'); in a file deeper in the application produces a undefined object, so I'm guessing that a server is a singleton object.
试图要求('./app'); 在应用程序更深处的文件中产生一个未定义的对象,所以我猜测服务器是一个单例对象。
It isn't true. require
always returns the reference to the module object. If you see undefined
, then you've messed up something else (altered the module itself?).
这不是真的。require
始终返回对模块对象的引用。如果你看到undefined
,那么你已经搞砸了其他东西(改变了模块本身?)。
Final note:I hope it helps a bit. Writing your own framework can be a difficult job, especially since there already are excelent frameworks like Express. Good luck though!
最后一点:我希望它有点帮助。编写自己的框架可能是一项艰巨的工作,尤其是因为已经有像 Express 这样的优秀框架。不过祝你好运!
EDIT
编辑
Implementing .get
and .set
methods is actually not difficult. You just need to alter route
function like this:
实现.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');
},
and then in routing algorithm you check whether type
property is defined. If it is not then use that route (undefined
type means: always route). Otherwise additionally check if a request's method matches type. And you're done!
然后在路由算法中检查是否type
定义了属性。如果不是,则使用该路由(undefined
类型表示:始终路由)。否则另外检查请求的方法是否与类型匹配。大功告成!