nodejs模块学习: connect2解析
nodejs 实践:express 最佳实践(七) 改造模块 connect2 解析
nodejs 发展很快,从 npm 上面的包托管数量就可以看出来。不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需要开发者创造大量的轮子来解决现实的问题。
知其然,并知其所以然这是程序员的天性。所以把常用的模块拿出来看看,看看高手怎么写的,学习其想法,让自己的技术能更近一步。
引言
上一篇文章中,我讨论了 connect 模块,它做为 http 的中间件,设计得很灵活,接口设计也很少,非常便于使用。
其实 connect 模块的思想就是把 http 请求和回应看成流水线,而中间件则是流水线上的处理器,满足路由匹配,则调用相应的方法,直到结果返回。
我就在想,这套思想能不能用在别的地方? 如 rpc, tcp 的请求处理,它们也都是一问一答的模式,也都可以抽象成流水线的模式进行处理,每个中间件对其中的数据进行处理,最后把结果返回了。
在仔细研究了 connect 的源码的基础上,我精减了部分代码,拿掉了 http 部分, 还有 url 匹配的部分,保留最有用的部分,同时增加了参数化配置和上下文环境。
于是就有了: connect2这个模块,最小化 connect 的功能,保留了 next 和错识处理等已知的概念,没有带它的功能。它可以做为一个基础的模块嵌入到一个 rpc,tcp , http 中去,然后利用中间件的思想去完成你的业务。
下面,就仔细说说,我对它的考虑和使用说明。
解析
我对该模块的第一个考虑就是,他的实现跟某种协议无关。可以看看 connect2 的使用方法:
var connect = require('connect2');
var app = connect();
app.use(function(ctx, req, res, next){
console.log('md1')
next()
});
app.use(function(ctx, req, res) {
console.log('md2')
next()
})
function main() {
let context = {};
let req = {};
let res = {};
app(context, req, res);
}
main();
可以看出,基本使用的方法于 connect 的模块相同,但是已经没有调用 http 的服务器了,它能在一个普通的函数中调用。
同时,多了一个 context, 这个我觉得挺重要的,用 express 做项目时,要跟踪请求全链路的路径,这在 java 中还好办,有 ThreadLocal 。这在 nodejs 中没有什么很好的办法,只能通过参数的形式,把 requestId 传下去。而 context 就是放这一类参数很好的地方。
有了这个 context 还可以把 协议 上下文也放到里面,实现更有用的功能。
导出函数是这样写的:
function createServer(opts) {
function app (ctx, req, res, next) { app.handle(ctx, req, res, next)}
Object.assign(app, proto);
Object.assign(app, opts);
Object.assign(app, EventEmitter.prototype);
app.stack = [];
app.route = '';
return app;
}
多了一个配置的 opts,会把 opts 的属性复制到 app 上面。后面会说一下有哪些方法可以配置。
而 use 方法也是基本没有怎么改变,删除了 http 的部分:
proto.use = function(route, fn) {
let handle = fn;
let path = route;
if (typeof route !== 'string') {
handle = route;
path = '';
}
if (typeof handle.handle === 'function') {
let server = handle;
server.route = path;
handle = function(ctx, req, res, next) {
server.handle(ctx, req, res, next);
};
}
this.stack.push({handle: handle, route: path});
}
下面说说其中的核心 handle 功能:
proto.handle = function(ctx, req, res, out) {
let i = 0;
let done = out || (this.finalHandler && this.finalHandler(ctx, req, res)) || NOOP;
let dispatchContext = (this.dispatchContext && this.dispatchContext()) || {};
let self = this;
Object.assign(ctx, {
app: this,
req: req,
res: res
})
let next = function(err) {
let layer = self.stack[i++]
if (!layer) {
defer(done, err)
return;
}
if (layer.route && self.dispatch && !self.dispatch(dispatchContext, layer.route, req)) {
return next(err)
}
debug('use %s %s', layer.route || 'none', layer.handle.name || 'anonymous');
call(layer.handle, layer.route, err, ctx, req, res, next);
}
next();
}
任何请求都有一个结束, 在 connect 中使用的是 finalhanlder 模块,也只能处理 http 问题,这里我们与 协议无关,因此这里就需要留下 一个接口,这个接口就通过 opts 进行配置的。
另外还有匹配参数的方法,dispatch 这块是把 url 参数匹配的算法移出,通过初始化参数的形式返回。
更多的例子可以在 test/server.js 中找到。
总结
connect2 就是对 connect 的一个精减。针对的更加普遍的问题,对一些东西能进行流水线的形式进行处理,将变化写成中间件,然后对所以的数据进行处理,在合适的时候返回。
特别合适网络服务器,自定义协议的部分,想想,通过这个模块,除了底层的协议,跟 http 不一样,其他都一样,这样写业务是不是很爽呢?
很快就要把这个模块融入到一个项目中,还有想把该项目给 typescript 化。
nodejs模块学习: connect2解析的更多相关文章
- # nodejs模块学习: express 解析
# nodejs模块学习: express 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需要开发者创造大量的轮子 ...
- nodejs模块学习: webpack
nodejs模块学习: webpack nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需要开发者创造大量的轮子来解决现实 ...
- nodejs模块学习: connect解析
nodejs模块学习: connect解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需要开发者创造大量的轮子来解决 ...
- nodejs模块学习: express-session 解析
nodejs模块学习: express-session 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需要开发者创 ...
- python模块学习---HTMLParser(解析HTML文档元素)
HTMLParser是Python自带的模块,使用简单,能够很容易的实现HTML文件的分析. 本文主要简单讲一下HTMLParser的用法. 使用时需要定义一个从类HTMLParser继承的类,重定义 ...
- nodejs 实践:express 最佳实践(七) 改造模块 connect2 解析
nodejs 实践:express 最佳实践(七) 改造模块 connect2 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的 ...
- nodeJS学习(9)--- nodeJS模块:exports vs module.exports
模块简介: 通过Node.js的官方API可以看到Node.js本身提供了很多核心模块 http://nodejs.org/api/ 这些核心模块被编译成二进制文件,可以 require('模块名') ...
- nodejs模块xml2js解析xml的坑
在一个项目中,用到nodejs模块xml2js解析xml,xml的数据如下: <xml> <MsgId>6197906553041859764</MsgId> &l ...
- NodeJS入门学习教程
一.概念 1.什么是nodejs Node.js是JavaScript 运行时环境,通俗易懂的讲,Node.js是JavaScript的运行平台 Node.js既不是语言,也不是框架,它是一个平台 2 ...
随机推荐
- php 关于经纬度距离计算方法 成功版
1.PHP实现通过经纬度计算距离 单位为公里 function getdistance($lng1,$lat1,$lng2,$lat2)//根据经纬度计算距离 { //将角度转为狐度 $radLat ...
- php实现题目抢答、商品秒杀等类型的需求
最近和其他部门合作项目,当然我是负责php接口方面的工作,get到一些东西,所以来分享记录一下. 项目需求: 题目将通过主持人ipad投射至大屏幕,选手按'抢答'按钮进行抢答.抢答成功,选手所在组,以 ...
- docker安装-centos7
操作系统要求 要安装Docker,您需要64位版本的CentOS 7.步骤: 卸载旧版本 Docker的旧版本被称为docker或docker-engine . 如果这些已安装,请卸载它们以及关联 ...
- 关于css中的position定位
希望这波position可以有帮助^_^! css中的position属性主要分为:static.relative.absolute.fixed.center.page.sticky(红色是css3中 ...
- 史上最完整Hadoop2.x完全分布式安装部署-小白也能学会
一.环境要求: 1. 虚拟机安装并设置网络: 2. 修改主机地址映射: 3. 必备软件:Jdk.Development Tools Development ...
- 禅道---Bug管理模块
禅道官网:http://www.cnezsoft.com/ 简介: 开源免费的项目管理软件.集产品管理.项目管理.测试管理一体以及事物管理组织管理的功能 使用原因: 开源 方便跟踪管理Bug 使用简单 ...
- Django中通过filter和simple_tag为前端实现自定义函数
Django的模板引擎提供了一般性的功能函数,通过前端可以实现多数的代码逻辑功能,这里称之为一般性,是因为它仅支持大多数常见情况下的函数功能,例如if判断,ifequal对比返回值等,但是稍微复杂一些 ...
- 用PHP和Ajax进行前后台数据交互——以用户登录为例
很多网站中都有用户登录系统,要完成用户的注册和登陆,就一定要用到前后台的数据交互.在这里以简单的用户注册和登陆为例介绍一下前后台交互的大致流程. 首先,我们来做一个简单的登陆界面. 这里为了方便我使用 ...
- 流畅的python学习笔记:第一章
这一章中作者简要的介绍了python数据模型,主要是python的一些特殊方法.比如__len__, __getitem__. 并用一个纸牌的程序来讲解了这些方法 首先介绍下Tuple和nametup ...
- Discuz添加自定义模板广告
在做Discuz中广告的时候碰到个大问题,现在我需要做一个轮播的通屏广告位,调用广告图片的代码应该是以下代码:<ul> <li style="background: ...