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 化。

connect2 github

nodejs 实践:express 最佳实践(七) 改造模块 connect2 解析的更多相关文章

  1. nodejs 实践:express 最佳实践系列

    nodejs 实践:express 最佳实践系列 nodejs 实践:express 最佳实践(一) 项目结构 nodejs 实践:express 最佳实践(二) 中间件 nodejs 实践:expr ...

  2. nodejs 实践:express 最佳实践(四) express-session 解析

    nodejs 实践:express 最佳实践(四) express-session 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs ...

  3. nodejs 实践:express 最佳实践 (一)

    express 最佳实践 (一) 最近,一直在使用 nodejs 做项目,对 nodejs 开发可以说深有体会. 先说说 nodejs 在业务中的脚色,, 在 web同构 方面, nodejs 的优势 ...

  4. nodejs 实践:express 最佳实践 (一) 项目结构

    express 最佳实践 (一) 第二篇: express 最佳实践(二):中间件 最近,一直在使用 nodejs 做项目,对 nodejs 开发可以说深有体会. 先说说 nodejs 在业务中的脚色 ...

  5. nodejs 实践:express 最佳实践(三) express 解析

    nodejs 实践:express 最佳实践(三) express 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固, ...

  6. nodejs 实践:express 最佳实践(五) connect解析

    nodejs 实践:express 最佳实践(五) connect解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需 ...

  7. nodejs 实践:express 最佳实践(二) 中间件

    express 最佳实践(二):中间件 第一篇 express 最佳实践(一):项目结构 express 中最重要的就是中间件了,可以说中间件组成了express,中间件就是 express 的核心. ...

  8. nodejs 实践:express 最佳实践(六) express 自省获得所有的路由

    nodejs 实践:express 最佳实践(六) express 自省获得所有的路由 某些情况下,你需要知道你的应用有多少路由,这在 express 中没有方法可以.因此我这边曲线了一下,做成了一个 ...

  9. nodejs 实践:express 最佳实践(八) egg.js 框架的优缺点

    nodejs 实践:express 最佳实践(八) egg.js 框架的优缺点 优点 所有的 web开发的点都考虑到了 agent 很有特色 文件夹规划到位 扩展能力优秀 缺点 最大的问题在于: 使用 ...

随机推荐

  1. <十七>UML核心视图动态视图之时序图

    一:时序图 --->时序图是用于描述按时间顺序排列的对象之间的交互模式. --->它按照参与交互的对象所具有的“生命线”和他们相互发送的消息来显示这些对象. --->时序图包含对象和 ...

  2. Java的Socket通信(多线程)(1)

    如图: 思路: ①首先创建服务器端Socket,指定并侦听某一个端口,然后循环监听开始等待客户端的连接…. ②创建客户端socket,指定服务器地址和端口,然后获取输出流,向服务器端发送请求,并关闭s ...

  3. 快速排序(java)

    快速排序是冒泡排序的优化,是一种非常高效的排序, 甚至是目前为止最高效的排序,其思想是这样的:设数组a中存放了n个数据元素,low为数组的低端下标,high为数组的高端下标,从数组a中任取一个元素(通 ...

  4. 创建oracle数据库图示(一步一步教你安装oracle)

    123456 密码 版权声明:本文为博主原创文章,未经博主允许不得转载.

  5. SVN&nbsp;被防火墙阻止的解决方法

    SVN 被防火墙阻止的解决方法: 1. 进入WIN7的防火墙,看到有的SVN服务是被阻止的,专用的和公用的要设置为允许被防火墙阻止的解决方法" TITLE="SVN 被防火墙阻止的 ...

  6. [开发技巧]·TensorFlow&Keras GPU使用技巧

    [开发技巧]·TensorFlow&Keras GPU使用技巧 ​ 1.问题描述 在使用TensorFlow&Keras通过GPU进行加速训练时,有时在训练一个任务的时候需要去测试结果 ...

  7. 如何让div中的span垂直居中 ----height:100%设置div的高度

    如果div中只有一个span一个元素,可以使用line-height.如果div中还有其他元素,可以设置span的css如下: .span{ position: absolute; top: 50%; ...

  8. 分层确定性钱包开发的代码实现(HD钱包服务)

    HD Wallets的全称是Hierachical Deterministic Wallets, 对应中文是 分层确定性钱包. 这种钱包能够使用一组助记词来管理所有的账户的所有币种,在比特币的BIP3 ...

  9. Ajax遇到的那些坑

    提前说明:这里我用的是Windows系统,所以解决问题的方法也是仅限Windows系统,浏览器使用Chrome 第一个坑:Access to XMLHttpRequest at 'file:///C: ...

  10. 使用docker搭建项目环境

    # 清屏 clear # 查看当前文件夹下的列表 ls # 跳目录 cd ~ 代表当前用户文件夹 cd / 代表根目录 cd..返回上一级目录 cd #sudo 使用超级管理员创建文件夹 不加sudo ...