什么是中间件?

     中间件是模拟现实中的一个策略,可以把一个http看作是污水处理流,中间件就像是一层层的过滤网。每个中间件在http处理过程中通过改写request或(和)response的数据、状态,实现了特定的功能。

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

express源码剖析1的更多相关文章

  1. express源码剖析2

    当使用express时,代码会这样写: var express = require('express'); 如果创建一个express的应用,代码会这样写: var app = express(); ...

  2. express源码剖析--Router模块

    1.加载模块执行代码: methods.forEach(function(method){ //method是http协议的各种请求方法,如:get,put,headee,post Route.pro ...

  3. Node 进阶:express 默认日志组件 morgan 从入门使用到源码剖析

    本文摘录自个人总结<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 章节概览 morgan是express默认的日志中间件, ...

  4. STL源码剖析——hashtable

    二叉搜索树具有对数时间的搜索复杂度,但是这样的复杂度是再输入数据有足够的随机性的假设上哈希表在插入删除搜索操作上也具有常数时间的表现,而且这种表现是以统计为基础,不需要依赖输入元素的随机性 hasht ...

  5. jQuery之Deferred源码剖析

    一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...

  6. Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现

    声明:本文为原创博文,转载请注明出处. Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程 ...

  7. Apache Spark源码剖析

    Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著   ISBN 978-7-121-25420- ...

  8. 基于mybatis-generator-core 1.3.5项目的修订版以及源码剖析

    项目简单说明 mybatis-generator,是根据数据库表.字段反向生成实体类等代码文件.我在国庆时候,没事剖析了mybatis-generator-core源码,写了相当详细的中文注释,可以去 ...

  9. STL"源码"剖析-重点知识总结

    STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...

随机推荐

  1. jquery ajax异步和同步从后天取值

    最近使用jquery的ajax,发现有些效果不对,ajax请求后返回的json串回来了,但是执行顺序有问题. var isReload = false; $.post('/home/DetectCac ...

  2. ajaxFileUpload插件

    关键词: $.ajaxFileUpLoad(); data status dataType 参考资料: http://www.cnblogs.com/kissdodog/archive/2012/12 ...

  3. 阿里云yum源安装

      1.先清理掉yum.repos.d下面的所有repo文件 [root@localhost yum.repos.d]# rm -rf * 2.下载repo文件  wget http://mirror ...

  4. <编程珠玑>笔记 (一) 问题-算法-数据结构

    1  精确描述问题 第一章强调的重点在于”精确的描述问题“,这是程序开发的第一步 -- "Problem definition" 1.1  Precise problem stat ...

  5. Spring事物管理

    spring事务配置的五种方式 前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的事务配置只 ...

  6. AtomicBoolean使用

    使用 AtomicBoolean 高效并发处理 "只初始化一次" 的功能要求: 1 private static AtomicBoolean initialized = new A ...

  7. Warning: strftime(): It is not safe to rely on the system's timezone settings.

    当运行程序时,会出现如下警告: Warning: strftime(): It is not safe to rely on the system's timezone settings. You a ...

  8. 《深入理解Java内存模型》读书总结

    概要 文章是<深入理解Java内容模型>读书笔记,该书总共包括了3部分的知识. 第1部分,基本概念 包括"并发.同步.主内存.本地内存.重排序.内存屏障.happens befo ...

  9. 解决 npm install xxx 卡住 的问题

    因为npm连接的数据源网站太慢,可以使用淘宝提供的npm数据源, npm config set registry https://registry.npm.taobao.org 之后就会快得飞起.

  10. FPGA与simulink联合实时环路系列——实验三 按键key

    实验三 按键key 实验内容 在FPGA的实验中,经常涉及到按键的使用,按键是必不可少的人机交互的器件之一,在这些实验中,有时将按键的键值读取显示到数码管.LCD或者是通过串口传送到PC的串口助手上进 ...