express路由探析(續)

  上一篇分析了express的路由機制,此次主要補充一些沒有說到的東西。html

  以前說到,Router是中間件容器,Route是路由中間件,他們各自維護一個stack數組,裏面存放layer,layer是封裝中間件的一個數據結構。其實Router中不只能存放通常的中間件,還能存放Router,這一點在源碼中能看的出來,由於Router的構造函數中返回的是一個router函數,而中間件的生成也須要一個處理程序(函數),那麼若是把Router()返回的處理程序做爲參數傳入中間件的生成方法中,就至關於Router中存放了一個Router中間件,只不過這兩個Router是兩個不一樣的實例。app.Router是最頂層的,裏面能夠包含新的Router,新的Router是做爲中間件添加到app.Router的,因爲Router的結構設計,能夠保證訪問到裏面每一箇中間件的處理程序,包括嵌套的Router裏面的每一箇中間件。從express -e projectName命令生成的項目模型中就包括這種用法,下面是projectName項目根目錄(不是express根目錄)下的app.js文件:web

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

var fs = require('fs');

var app = express();  

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));  //從這裏這裏開始添加中間件,由於以前沒添加過,因此會實例化一個Router,在實例化的時候會添加兩個中間件(query和init),所以這個中間件是第三個
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes); //routes是「./routes/index.js」文件中建立的Router實例,也就是經過這句代碼在頂層Router裏面添加了新的Router
app.use('/users', users);

//var count = routes.stack.length;
var count = app._router.stack.count;
var content = "";
console.log(count);
/*for (var i = 0; i<count; i++) {
    content+=dump_obj(routes.stack[i]) + "\r\n\r\n";
    console.log(app._router.stack[i]);
};*/

console.log(app._router.stack[7]);  //輸出頂層Router中的一個特殊中間件,即app.use('/',routes)語句添加的routes,該中間件也是Router對象

/*fs.writeFile('message.txt', content, function (err) {
  if (err) throw err;
  console.log('It\'s saved!');
});

function dump_obj(myObject) {  
  var s = "";  
  for (var property in myObject) {  
   s = s + "\n "+property +": " + myObject[property] ;  
  }  
  return s;
}*/
// catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); // error handlers // development error handler // will print stacktrace if (app.get('env') === 'development') { app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); } // production error handler // no stacktraces leaked to user app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); module.exports = app;

下面是./routes/index.js的代碼,在裏面新實例化了一個Router對象,而後在該對象上添加了5箇中間件express

var express = require('express');
var router = express.Router();  //這裏新實例化一個Router,直接調用app(application.js)中的app.use()或app[method]能保證在app中的Router實例只有一個,可是咱們仍然能夠再手動實例化新的Router,app.Router實際上是最頂層的中間件容器,只能有一個

var users = {
    'byvoid':{
        name : "Carbo",
        website : 'http://www.byvoid.com'
    }
};

/*--------- test start 下面是測試代碼,在新建立的Router中添加中間件,待會兒要輸出進行驗證 ---------*/
var route = router.route('/user');
route.get(function(req,res,next){},function(req,res){});  //第一個中間件添加了兩個處理函數,下面的輸出會進行驗證

router.all('user/:username',function(req,res,next){
    if(users[req.params.username]){
        next();
    }
    else{
        next(new Error(req.params.username+'does not exist.'));
    }
});

router.get('/user/:username',function(req,res){
    res.send(JSON.stringify(users[req.params.username]));
});

router.get('/user/:username',function(req,res){ res.send('user:' + req.params.username); });
/*--------- test end -----------*/
 
/* GET home page. */
router.get('/', function(req, res) {
  res.render('index', { title: 'Express' });
});

module.exports = router;

運行後的輸出以下:json

新建立的Router(這裏只是做爲一箇中間件): /*該Router對象中添加了5箇中間件,能夠看到第一個中間件的stack中有兩個元素,與上面代碼相對應,這裏用橙色標出*/數組

{ path: '/user',cookie

  stack: 數據結構

   [ { handle: [Function],app

       name: '<anonymous>',函數

       params: undefined,測試

       path: undefined,

       keys: [],

       regexp: /^\/?$/i,

       method: 'get' },

     { handle: [Function],

       name: '<anonymous>',

       params: undefined,

       path: undefined,

       keys: [],

       regexp: /^\/?$/i,

       method: 'get' } ],

  methods: { get: true } }

{ path: 'user/:username',

  stack: 

   [ { handle: [Function],

       name: '<anonymous>',

       params: undefined,

       path: undefined,

       keys: [],

       regexp: /^\/?$/i,

       method: undefined } ],

  methods: { _all: true } }

{ path: '/user/:username',

  stack: 

   [ { handle: [Function],

       name: '<anonymous>',

       params: undefined,

       path: undefined,

       keys: [],

       regexp: /^\/?$/i,

       method: 'get' } ],

  methods: { get: true } }

{ path: '/user/:username',

  stack: 

   [ { handle: [Function],

       name: '<anonymous>',

       params: undefined,

       path: undefined,

       keys: [],

       regexp: /^\/?$/i,

       method: 'get' } ],

  methods: { get: true } }

{ path: '/',

  stack: 

   [ { handle: [Function],

       name: '<anonymous>',

       params: undefined,

       path: undefined,

       keys: [],

       regexp: /^\/?$/i,

       method: 'get' } ],

  methods: { get: true } }

9

頂層Router(中間件容器): /*下面是頂層Router中的第7箇中間件,該中間件也是個Router,藍色部分是封裝了子Router的Layer,子Router中的stack中有5個路由中間件,也就是上面輸出的5個;子Router是handler(中間件處理程序)的屬性值,也就是說這個子Router是做爲普通中間件添加到app.Router中的*/

{ handle:   

   { [Function: router]

     params: {},

     _params: [],

     caseSensitive: undefined,

     mergeParams: undefined,

     strict: undefined,

     stack: [ [Object], [Object], [Object], [Object], [Object] ] },

  name: 'router',

  params: undefined,

  path: undefined,

  keys: [],

  regexp: { /^\/?(?=\/|$)/i fast_slash: true },

  route: undefined }

  既然app.Router中能夠添加Router對象,那麼咱們能夠新建一個js文件,專門用來添加自定義的中間件,在該js文件中裏面實例化一個Router對象,將路由的註冊或非路由中間件的添加代碼都寫到該文件裏,而後導出該Router對象,最後在app.js中將該Router添加到app.Router中。

相關文章
相關標籤/搜索