什么是中间件?
1.EventEmitter.prototype
mixin(app, EventEmitter.prototype, false);
app为一个函数,也是对象,mixin是一个类库(merge-descriptors)。它就是一种mixin设计模式,作用是让app这个对象具有EventEmitter.prototype的方法。第三个参数表示“是否重新定义app中与EventEmitter.prototype中存在重名的方法。
EventEmitter类是nodejs中event的一个类,也是唯一类。它的核心是对事件触发与事件监听功能的封装。
EventEmitter实例的产生?
大多数 Node.js 核心 API 都是采用惯用的异步事件驱动架构,其中某些类型的对象(称为触发器)会周期性地触发命名事件来调用函数对象(监听器)。
Node.js里面的许多对象都会分发事件:一个net.Server对象(创建TCP或本地服务器)会在每次有新连接时分发一个事件, 一个fs.readStream对象会在文件被打开的时候发出一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。
EventEmitter类的使用
1.1 newListener事件
当注册一个事件时,触发newListener事件,例如:
var MyEmitter = require("events"); const myEmitter = new MyEmitter(); // Only do this once so we don't loop forever //当新的监听器被添加时,所有的 EventEmitter 会触发 'newListener' 事件; //当移除已存在的监听器时,则触发 'removeListener'。 myEmitter.once('newListener', (event, listener) => { if (event === 'event') { // Insert a new listener in front myEmitter.on('event', () => { console.log('B'); }); } }); myEmitter.on('event', () => { console.log('A'); }); myEmitter.emit('event'); //B //A
1.2 EventEmitter.defaultMaxListeners
唯一的静态成员,默认值是10,表示对应监听同一的事件个数是10个,不建议修改这个参数,否则会影响到所有EventEmitter实例的。
1.3 EventEmitter的prototype对象
var MyEmitter = require('events'); console.log(MyEmitter.prototype);
//结果是:
EventEmitter {
domain: undefined,
_events: undefined,
_maxListeners: undefined,
setMaxListeners: [Function: setMaxListeners],
getMaxListeners: [Function: getMaxListeners],
emit: [Function: emit],
addListener: [Function: addListener],
on: [Function: addListener],
once: [Function: once],
removeListener: [Function: removeListener],
removeAllListeners: [Function: removeAllListeners],
listeners: [Function: listeners],
listenerCount: [Function: listenerCount] }
[Finished in 0.3s]
app对象(函数)它具有以上方法,即app继承了EventEmitter的原型对象,值得注意的是:大部分模块继承自Event模块。
在express中的应用中,app对象通过on绑定了mount事件,如下:
//这个函数的重点是parent参数 this.on('mount', function onmount(parent) { // inherit trust proxy if (this.settings[trustProxyDefaultSymbol] === true //parent.settings['trust proxy fn'] = compileTrust(val) && typeof parent.settings['trust proxy fn'] === 'function') { delete this.settings['trust proxy']; delete this.settings['trust proxy fn']; } // inherit protos this.request.__proto__ = parent.request; this.response.__proto__ = parent.response; this.engines.__proto__ = parent.engines; this.settings.__proto__ = parent.settings; });
下面是利用到的中间件
array-flatten
有一个函数flattern,它的作用是把数组从多维变成一维,例如:
var flatten = require('array-flatten'); var arr = [1,2,5,[1,3]]; console.log(flatten(arr)); //[1,2,5,1,3]
finalhandler
finalhandler的作用就是一个http请求的最后一步的处理方式,
var finalhandler = require('finalhandler'); /*从handler传递过来的callback为undefined, finalhandler返回一个函数,这个函数可以出发done(err), 如果err为false,它将在res写入404,否则,会在res中写入错误信息。 */ var done = callback || finalhandler(req, res, { env: this.get('env'), onerror: logerror.bind(this) });
parseUrl
var req1 = {
url: "http://localhost:4000/m/xx/login.html?kf=33",
};
var str = parseUrl(req1);
console.log("str=",str);
//str= Url {
protocol: 'http:',
slashes: true,
auth: null,
host: 'localhost:4000',
port: '4000',
hostname: 'localhost',
hash: null,
search: '?kf=33',
query: 'kf=33',
pathname: '/m/xx/login.html',
path: '/m/xx/login.html?kf=33',
href: 'http://localhost:4000/m/xx/login.html?kf=33',
_raw: 'http://localhost:4000/m/xx/login.html?kf=33' }
类似url包中parse方法
var url = require('url'); var testStr = "http://www.sina.com//xx/y/z.html?ss=1&s=2"; //第二个参数为false,返回对象中query为字符串。第三个参数看文档测试没什么鸟用 console.log(url.parse(testStr,false,true)); console.log(url.parse(testStr,true,true)); console.log(url.parse(testStr,true,false)); /* Url { protocol: 'http:', slashes: true, auth: null, host: 'www.sina.com', port: null, hostname: 'www.sina.com', hash: null, search: '?ss=1&s=2', query: 'ss=1&s=2', pathname: '//xx/y/z.html', path: '//xx/y/z.html?ss=1&s=2', href: 'http://www.sina.com//xx/y/z.html?ss=1&s=2' } Url { protocol: 'http:', slashes: true, auth: null, host: 'www.sina.com', port: null, hostname: 'www.sina.com', hash: null, search: '?ss=1&s=2', query: { ss: '1', s: '2' }, pathname: '//xx/y/z.html', path: '//xx/y/z.html?ss=1&s=2', href: 'http://www.sina.com//xx/y/z.html?ss=1&s=2' } Url { protocol: 'http:', slashes: true, auth: null, host: 'www.sina.com', port: null, hostname: 'www.sina.com', hash: null, search: '?ss=1&s=2', query: { ss: '1', s: '2' }, pathname: '//xx/y/z.html', path: '//xx/y/z.html?ss=1&s=2', href: 'http://www.sina.com//xx/y/z.html?ss=1&s=2' } */
pathRegexp
在Layer.js中利用到。path-to-regexp是express的路由规则,初始化pathRegexp有三个参数:path(可以是正则表达式),key(对path中关键字填充的数组)和options,options包括三个参数,
分别是end,caseSensitive和strict,具体可以参考http://blog.csdn.net/chszs/article/details/51055229。
var pathRegexp = require('path-to-regexp'); /* var layer = Layer('/', {}, handle); this.keys是对path中参数的一种解释。如path="/user/:foo",那么keys= [name:"foo",delimiter:"false"] */ this.regexp = pathRegexp(path, this.keys = [], opts); // end为false时,正则从path开始进行匹配,相当于^ if (path === '/' && opts.end === false) { this.regexp.fast_slash = true; }
看下面一个例子:
function test(){ var keys = [], opts= { "sensitive":false, "strict":false, "end":false }, regexp = pathRegexp("/user/:id/:page/", keys = [], opts); var m = regexp.exec("/user/anthonyliu/your"); console.log("m="+JSON.stringify(m)); } test(); //第一个元素是输入的路径,后面都是匹配的分组! //m=["/user/anthonyliu/your","anthonyliu","your"]
compileQueryParser
var compileQueryParser = require('./utils').compileQueryParser; compileQueryParser("extended");
qs是express依赖的包
他只提供两个方法:parse,和stringify,qs.parse作为回调函数传递给middleware/query。query返回一个函数,给rounter.use调用。
/* middlemare/query,返回该函数,给rounter.user */ return function query(req, res, next){ if (!req.query) { var val = parseUrl(req).query; req.query = queryparse(val, opts); } next(); }; };