还没用express
写过server
,先把部份源码撸了一遍,列位大神求轻拍。
express
进口文件在lib
文件夹下的express.js
,其向外界暴露了一些要领。
最主要的(express.js
第36-47行):
function createApplication() {
var app = function(req, res, next) {
app.handle(req, res, next); //各中心件的处置惩罚进口,handle要领经由过程mixin拓展于proto
};
mixin(app, EventEmitter.prototype, false);
mixin(app, proto, false);
app.request = { __proto__: req, app: app };
app.response = { __proto__: res, app: app };
app.init();
return app;
}
exports = module.exports = createApplication;
我们经常在本身的营业代码中如许写:
var express = require('express');
var app = express();
实在就是挪用createApplication
要领.如许就实例化了一个app。这个app
比较特别,经由过程mixin
集成了一些其他的属性
mixin(app, EventEmitter.prototype, false); //拓展了事宜发射器原型对象
mixin(app, proto, false); //拓展了application.js中的属性和要领
在我们营业代码实例化app
的时刻,挪用了app.init()
要领完成了一些初始化的设置。init()
要领也是从application.js
中继续的。
进口文件很清楚,主假如完成要领的暴露以及app
的一些初始化操纵。
接下来看下application.js
中的部份代码逻辑:
第136-146行,耽误实例化一个_router
app.lazyrouter = function lazyrouter() {
if (!this._router) {
this._router = new Router({
caseSensitive: this.enabled('case sensitive routing'),
strict: this.enabled('strict routing')
});
this._router.use(query(this.get('query parser fn')));
this._router.use(middleware.init(this));
}
};
第157-174行,这是各个middleware
的进口,
app.handle = function handle(req, res, callback) {
var router = this._router; //猎取已实例化得router
// final handler
var done = callback || finalhandler(req, res, {
env: this.get('env'),
onerror: logerror.bind(this)
});
// no routes
if (!router) {
debug('no routes defined on app');
done();
return;
}
router.handle(req, res, done); //当http过来时,关于request和response的处置惩罚从这个处所最先
};
第187-242行,app.use
要领供应了运用级的middleware
,然则事实上在214行,this.lazyrouter()
新建一个route,第219-221行,然后依据app.use(fn)
传入的参数挂载到了route.use()
路由级中心件上了。app.use()
是route.use
的一个代办。
app.use = function use(fn) {
var offset = 0;
var path = '/';
// default path to '/'
// disambiguate app.use([fn])
if (typeof fn !== 'function') {
var arg = fn;
while (Array.isArray(arg) && arg.length !== 0) {
arg = arg[0];
}
// first arg is the path
if (typeof arg !== 'function') {
offset = 1;
path = fn;
}
}
var fns = flatten(slice.call(arguments, offset)); //摊平arguments
if (fns.length === 0) {
throw new TypeError('app.use() requires middleware functions');
}
// setup router
this.lazyrouter(); //假如没有route实例则新建一个
var router = this._router;
fns.forEach(function (fn) {
// non-express app //假如传入的不是express实例app
if (!fn || !fn.handle || !fn.set) {
return router.use(path, fn); //将中心件注入到router中
}
debug('.use app under %s', path);
fn.mountpath = path;
fn.parent = this;
// restore .app property on req and res
router.use(path, function mounted_app(req, res, next) {
var orig = req.app;
fn.handle(req, res, function (err) {
req.__proto__ = orig.request;
res.__proto__ = orig.response;
next(err);
});
});
// mounted an app
fn.emit('mount', this);
}, this);
return this;
};
第255-258行,代办到router
实例的route()
的要领中:
app.route = function route(path) {
this.lazyrouter();
return this._router.route(path);
};
router
实例是经由过程router/index.js
供应组织函数来建立的,在这个文件夹中第42-60行:
var proto = module.exports = function(options) {
var opts = options || {};
function router(req, res, next) {
router.handle(req, res, next); //handle要领继续于proto
}
// mixin Router class functions
router.__proto__ = proto;
router.params = {};
router._params = [];
router.caseSensitive = opts.caseSensitive;
router.mergeParams = opts.mergeParams;
router.strict = opts.strict;
router.stack = []; //初始化一个stack.这个stack中保留了注册的一切中心件
return router;
};
供应了一个router
的组织函数,它的原型对象上,第136行供应了proto.handle
要领,这个要领的作用就是吸收来自http
的req
和res
。
第413行,供应了proto.use
要领,正如上面所说的app.use
是route.use
的代办,这个要领的特别性就在任何的http
要求都邑经由在app.use
上挂载的中心件,比方如今express4.x
已将许多中心件从本身移除,须要你从新经由过程npm
去装置,然后在营业代码中举行援用,比方运用body-parser
中心件:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json());
如许每次http
要求过来的时刻起首会经由bodyParser.json()
这个中心件,它供应了一个向req
增加req.body = {}
要领,并传向下一个中心件的作用。
同时在route.use
内部,第439-458行,
for (var i = 0; i < callbacks.length; i++) {
var fn = callbacks[i];
if (typeof fn !== 'function') {
throw new TypeError('Router.use() requires middleware function but got a ' + gettype(fn));
}
// add the middleware
debug('use %s %s', path, fn.name || '<anonymous>');
var layer = new Layer(path, { //新建一个layer,layer上挂载了error_handler和request_handler
sensitive: this.caseSensitive,
strict: false,
end: false
}, fn);
layer.route = undefined;
this.stack.push(layer); //route本身会保护一个stack,将每一个新建的layer都推入stack当中,这个layer实例终究会对婚配的path,作出error_handle或许request_handle。
}
第477行,proto.route
要领供应了一个新建route的要领。
proto.route = function route(path) {
var route = new Route(path); //新建一个route,这个Route构建函数内部完成见./route.js,它内里供应了一个空的stack,用以
var layer = new Layer(path, { //新建一个layer,layer的作用见下面的解说
sensitive: this.caseSensitive,
strict: this.strict,
end: true
}, route.dispatch.bind(route));
layer.route = route;
this.stack.push(layer); //新建一个route,这个route会保护本身的stack
return route;
};
var route = require('express').Router()
,然则这个要领差别的处所
在于,它会本身保护一个stack
,这个stack
中有你在这个要领上面定义的一切中心件。一样,你能够经由过程这个route
挂载关于差别途径的req
, res
的处置惩罚。
运用的要领:
var express = require('express');
var app = express();
var router = express.Router();
//没有挂载任何途径的中心件,经由过程该路由的每一个要求都邑实行该中心件
router.use(function(req, res, next) {
console.log('route.use');
})
router.get('/test', function(req, res, next) {
console.log('route.get');
});
//末了须要将这个router挂载到运用
app.use('/', router);
以上部份主假如全部express
的中心件的挂载。总结一下:
经由过程
app.use()
挂载的中心件终究都代办到了router.use()
要领下router.use()
要领,新建一个layer
,layer
上保留了途径,默以为'/'
,及响应的处置惩罚要领,并存入这个app
保护的stack
中。经由过程
var router = require('express').Router()
新建的router
途径级实例,一样能够挂载差别的中心件,不过末了须要将这个router
路由注入到app
运用当中:app.use('/', router);
接下来说下当http
要求到来的时刻,数据的流向: 在你定义中心件的过程当中,由于是保护了一个app
或许route
实例,它们离别都有一个stack
。这个stack
是FIFO
的,因而每当一个要求过来的时刻,数据从最最先的定义的中心件最先,一向向下按递次举行通报,因而你能够本身定义,固然,你须要挪用next()要领。就比方Route.protoype.dispath
要领
//将req, res分发给这个route
Route.prototype.dispatch = function dispatch(req, res, done) {
var idx = 0;
var stack = this.stack;
if (stack.length === 0) {
return done();
}
var method = req.method.toLowerCase();
if (method === 'head' && !this.methods['head']) {
method = 'get';
}
req.route = this;
next();
function next(err) {
if (err && err === 'route') {
return done();
}
var layer = stack[idx++];
if (!layer) {
return done(err);
}
if (layer.method && layer.method !== method) { //婚配传入的req要求体式格局,和layer的method举行对照
return next(err);
}
//挪用layer.handle,用以错误处置惩罚或许request处置惩罚
if (err) {
layer.handle_error(err, req, res, next);
} else {
layer.handle_request(req, res, next);
}
}
};
末了,http
要求的处置惩罚:
在app
或许route
实例中,本身有一个stack
,这个stack
就存放了在挂载中心时新建的layer
,每一个layer
实例都保留了对应的途径,以及响应的error_handle
和request_handle
。
感谢人人看到这里,迎接人人指正。
下一篇写写express
路由的完成。