Using routes in Express-js

2019-01-29 20:20发布

问题:

So I'm starting to use Node.js. I saw the video with Ryan Dahl on Nodejs.org and heard he recommended Express-js for websites.

I downloaded the latest version of Express, and began to code. I have a fully fledged static view up on /, but as soon as I try sending parameters, I get errors like this:

Cannot GET /wiki

I tried following the guide on expressjs.com but the way one uses routes has changed in the latest version, which makes the guide unusable.

Guide:

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

Generated by Express:

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

My problem arises when I try and add another route.

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

I've tried a bunch of approaches, but I keep getting the Cannot GET /wiki (404) error.

routes/index.js looks like this:

exports.index = function(req, res) {
    res.render('index', { title: 'Test', articles: articles, current_article: current_article, sections: sections })
};

The only thing I did there was add some parameters (arrays in the same file) and this i working. But when I copy the contents and change exports.index to exports.wiki or exports.wiki_show I still get the Cannot GET /wiki error.

Can anyone explain to me what I'm missing here? - Thanks.

回答1:

So, after I created my question, I got this related list on the right with a similar issue: Organize routes in Node.js.

The answer in that post linked to the Express repo on GitHub and suggests to look at the 'route-separation' example.

This helped me change my code, and I now have it working. - Thanks for your comments.

My implementation ended up looking like this;

I require my routes in the app.js:

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

And I add my routes like this:

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

I have two files called wiki.js and site.js in the root of my app, containing this:

exports.edit = function(req, res) {

    var wiki_entry = req.params.id;

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


回答2:

The route-map express example matches url paths with objects which in turn matches http verbs with functions. This lays the routing out in a tree, which is concise and easy to read. The apps's entities are also written as objects with the functions as enclosed methods.

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


回答3:

Seems that only index.js get loaded when you require("./routes") . I used the following code in index.js to load the rest of the routes:

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];
  }
});


回答4:

You could also organise them into modules. So it would be something like.

./
controllers
    index.js
    indexController.js
app.js

and then in the indexController.js of the controllers export your controllers.

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

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

then in index.js of controllers dir

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

and finally in app.js

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

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

I think this approach allows for clearer seperation and also you can configure your controllers by passing perhaps a db connection in.