Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1495248
  • 博文数量: 148
  • 博客积分: 2234
  • 博客等级: 大尉
  • 技术积分: 3225
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-17 21:34
个人简介

未来很长。

文章存档

2017年(7)

2016年(4)

2015年(1)

2014年(6)

2013年(31)

2012年(99)

分类: LINUX

2013-11-19 16:07:30

Connect模块背景

Node.js的愿望是成为一个能构建高速,可伸缩的网络应用的平台,它本身具有基于事件,异步,非阻塞,回调等特性,这在前几篇专栏中有过描述。 正是基于这样的一些特性,Node.js平台上的Web框架也具有不同于其他平台的一些特性,其中Connect是众多Web框架中的佼佼者。
Connect在它的官方介绍中,它是Node的一个中间件框架。超过18个捆绑的中间件和一些精选第三方中间件。尽管Connect可能不是性能最好的 Node.jsWeb框架,但它却几乎是最为流行的Web框架。为何Connect能在众多框架中胜出,其原因不外乎有如下几个:

  • 模型简单
  • 中间件易于组合和插拔
  • 中间件易于定制和优化
  • 丰富的中间件

Connect自身十分简单,其作用是基于Web服务器做中间件管理。至于如何如何处理网络请求,这些任务通过路由分派给管理的中间件们进行处理。 它的处理模型仅仅只是一个中间队列,进行流式处理而已,流式处理可能性能不是最优,但是却是最易于被理解和接受。基于中间件可以自由组合和插拔的情况,优 化它十分容易。
Connect模块目前在NPM仓库的MDO(被依赖最多的模块)排行第八位。但这并没有真实反映出它的价值,因为排行第五位的Express框架实际上是依赖Connect创建而成的。关于Express的介绍,将会在后续的专栏中一一为你讲解。

让我们回顾一下Node.js最简单的Web服务器是如何编写的:

点击(此处)折叠或打开

  1. var http = require('http');
  2. http.createServer(function (req, res) {
  3.   res.writeHead(200, {'Content-Type': 'text/plain'});
  4.   res.end('Hello World\n');
  5. }).listen(1337, '127.0.0.1');
我们从最朴素的Web服务器处理流程开始,可以看到HTTP模块基于事件处理网络访问无外乎两个主要的因素,请求和响应。同理的是Connect的中间件也是扮演这样一个角色,处理请求,然后响应客户端或是让下一个中间件继续处理。如下是一个中间件最朴素的原型:

点击(此处)折叠或打开

  1. function (req, res, next) {
  2.   // 中间件
  3. }

在中间件的上下文中,有着三个变量。分别代表请求对象、响应对象、下一个中间件。如果当前中间件调用了res.end()结束了响应,执行下一个中间件就显得没有必要。

为了演示中间件的流式处理,我们可以看看中间件的使用形式:

点击(此处)折叠或打开

  1. var app = connect();
  2. // Middleware
  3. app.use(connect.staticCache());
  4. app.use(connect.static(__dirname + '/public'));
  5. app.use(connect.cookieParser());
  6. app.use(connect.session());
  7. app.use(connect.query());
  8. app.use(connect.bodyParser());
  9. app.use(connect.csrf());
  10. app.use(function (req, res, next) {
  11.   // 中间件
  12. });
  13. app.listen(3001);
Conncet提供use方法用于注册中间件到一个Connect对象的队列中,我们称该队列叫做中间件队列。



Conncet的部分核心代码如下,它通过use方法来维护一个中间件队列。然后在请求来临的时候,依次调用队列中的中间件,直到某个中间件不再调用下一个中间件为止。


点击(此处)折叠或打开

  1. app.stack = [];
  2. app.use = function(route, fn){
  3.   // …

  4.   // add the middleware
  5.   debug('use %s %s', route || '/', fn.name || 'anonymous');
  6.   this.stack.push({ route: route, handle: fn });

  7.   return this;
  8. };

值得注意的是,必须要有一个中间件调用res.end()方法来告知客户端请求已被处理完成,否则客户端将一直处于等待状态。
流式处理也是Node.js中用于流程控制的经典模式,Connect模块是典型的应用了它。流式处理的好处在于,每一个中间层的职责都是单一的,开发者通过这个模式可以将复杂的业务逻辑进行分解。

路由

从前文可以看到其实app.use()方法接受两个参数,route和fn,既路由信息和中间件函数,一个完整的中间件,其实包含路由信息和中间件函数。路由信息的作用是过滤不匹配的URL。请求在遇见路由信息不匹配时,直接传递给下一个中间件处理。
通常在调用app.use()注册中间件时,只需要传递一个中间件函数即可。实际上这个过程中,Connect会将/作为该中间件的默认路由,它表示所有的请求都会被该中间件处理。
中间件的优势类似于Java中的过滤器,能够全局性地处理一些事务,使得业务逻辑保持简单。
任何事物均有两面性,当你调用app.use()添加中间件的时候,需要考虑的是中间件队列是否太长,因为每一层中间件的调用都是会降低性能的。为了提高性能,在添加中间件的时候,如非全局需求的,尽量附带上精确的路由信息。
以multipart中间件为例,它用于处理表单提交的文件信息,相对而言较为耗费资源。它存在潜在的问题,那就是有可能被人在客户端恶意提交文件,造成服务器资源的浪费。如果不采用路由信息加以限制,那么任何URL都可以被攻击。


app.use("/upload", connect.multipart({ uploadDir: path }));
阅读(2107) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~