在Express-js中使用路由

48

我开始使用Node.js。我看了Ryan Dahl在Nodejs.org上的视频,听说他推荐Express-js用于网站。

我下载了最新版本的Express,并开始编码。我已经在/上拥有一个完整的静态视图,但是一旦我尝试发送参数,就会出现以下错误:

Cannot GET /wiki

我尝试遵循expressjs.com上的指南,但最新版本中路由的使用方式已更改,这使得该指南无法使用。

指南:

app.get('/users/:id?', function(req, res, next){
    var id = req.params.id;
    if (id) {
        // do something
    } else {
        next();
    }
});

由Express生成:

app.get('/', routes.index);

当我尝试添加另一条路由时,就会出现问题。

app.get('/wiki', routes.wiki_show);

我已尝试了许多方法,但仍然遇到“Cannot GET /wiki”(404)错误。

routes/index.js看起来像这样:
exports.index = function(req, res) {
    res.render('index', { title: 'Test', articles: articles, current_article: current_article, sections: sections })
};

我在那里做的唯一一件事就是添加了一些参数(在同一个文件中的数组),这个是有效的。但是当我复制内容并将 exports.index 更改为 exports.wikiexports.wiki_show 时,仍然会出现 Cannot GET /wiki 错误。

有人能向我解释我错过了什么吗?- 谢谢。


你添加了路由中间件吗? - fent
你下载了最新的Express吗?是从Github还是通过NPM获取的? - Ryan Olds
1
@DeaDEnD 是的,我非常确定 :) - Andreas Stokholm
@RyanOlds 我从GitHub上获取了它 :) - Andreas Stokholm
主程序不稳定。使用NPM安装,您应该获得2.5.6版本。此外,当您指定路由时,路由器中间件会自动绑定。 - Ryan Olds
谢谢@RyanOlds - 我刚刚通过NPM安装了它,这似乎更加稳定。 - Andreas Stokholm
5个回答

76

所以,在我创建了我的问题之后,右侧出现了一个相关列表,其中包含一个类似的问题:如何在Node.js中组织路由

那篇文章中的答案链接到了GitHub上的Express仓库,并建议查看“route-separation”示例。

这帮助我改变了我的代码,现在它可以工作了。- 感谢您的评论。

我的实现最终看起来像这样:

我在app.js中要求我的路由:

var express = require('express')
  , site = require('./site')
  , wiki = require('./wiki');

我是这样添加路由的:

app.get('/', site.index);
app.get('/wiki/:id', wiki.show);
app.get('/wiki/:id/edit', wiki.edit);

我有两个文件分别叫做wiki.js和site.js,它们在我的应用程序根目录下,内容如下:

exports.edit = function(req, res) {

    var wiki_entry = req.params.id;

    res.render('wiki/edit', {
        title: 'Editing Wiki',
        wiki: wiki_entry
    })
}

3
Express非常好用。作为初学者,从零开始构建一个Web服务器是很有用的,可以更好地理解Node。我在这里找到了一个教程,先学完了它,然后就直接转向Express了:http://nodebeginner.org/。 - bryanmac

10

route-map示例在Express中将URL路径与对象匹配,然后将HTTP动词与函数匹配。这样可以使用树形结构来布置路由,既简洁又易于阅读。该应用程序的实体也编写为带有函数作为封闭方法的对象。

var express = require('../../lib/express')
  , verbose = process.env.NODE_ENV != 'test'
  , app = module.exports = express();

app.map = function(a, route){
  route = route || '';
  for (var key in a) {
    switch (typeof a[key]) {
      // { '/path': { ... }}
      case 'object':
        app.map(a[key], route + key);
        break;
      // get: function(){ ... }
      case 'function':
        if (verbose) console.log('%s %s', key, route);
        app[key](route, a[key]);
        break;
    }
  }
};

var users = {
  list: function(req, res){
    res.send('user list');
  },

  get: function(req, res){
    res.send('user ' + req.params.uid);
  },

  del: function(req, res){
    res.send('delete users');
  }
};

var pets = {
  list: function(req, res){
    res.send('user ' + req.params.uid + '\'s pets');
  },

  del: function(req, res){
    res.send('delete ' + req.params.uid + '\'s pet ' + req.params.pid);
  }
};

app.map({
  '/users': {
    get: users.list,
    del: users.del,
    '/:uid': {
      get: users.get,
      '/pets': {
        get: pets.list,
        '/:pid': {
          del: pets.del
        }
      }
    }
  }
});

app.listen(3000);

5

看起来当你require("./routes")时只会加载index.js文件。我在index.js中使用了以下代码来加载其他路由:

var fs = require('fs')
  , path = require('path');

fs.readdirSync(__dirname).forEach(function(file){
  var route_fname = __dirname + '/' + file;
  var route_name = path.basename(route_fname, '.js');
  if(route_name !== 'index' && route_name[0] !== "."){ 
    exports[route_name] = require(route_fname)[route_name];
  }
});

这是一个不错的方法,如果你没有按照某种命名空间对路由进行分组,可以避免大量使用require语句。 - ZachB
实际上,将最后一行更改为exports [route_name] = require(route_fname)使您可以稍后通过命名空间引用路由,例如routes.users.show - ZachB

4
您也可以将它们组织成模块。因此,它会变成这样。
./
controllers
    index.js
    indexController.js
app.js

然后,在controllers的indexController.js中导出你的控制器。

//indexController.js
module.exports = function(){
//do some set up

var self = {
     indexAction : function (req,res){
       //do your thing
}
return self;
};

然后,在控制器目录的index.js中

exports.indexController = require("./indexController");

最后,在app.js中实现

var controllers = require("./controllers");

app.get("/",controllers.indexController().indexAction);

我认为这种方法能够更清晰地分离,同时你可以通过传递数据库连接来配置你的控制器。

1

没有人应该不停地写app.use('/someRoute', require('someFile'))直到代码成为一堆。

花时间调用/定义路由根本没有意义。即使您需要自定义控件,也可能只是部分时间需要,并且大多数时间您希望能够创建标准的文件结构以自动完成模块。

尝试Route Magic

随着应用程序规模的扩大,路由调用将开始形成一个巨大的代码堆,毫无意义。您希望使用Route Magic仅执行2行代码来处理所有app.use路由调用,如下所示:

const magic = require('express-routemagic')
magic.use(app, __dirname, '[your route directory]')

对于那些想要手动处理的文件夹,只需不将其传递给Magic即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接