JSGI and Stick

JSGI and Stick

 

这篇文档将描述一个构建web应用程序的框架(framework),该架构构建在JSGI规范基础上,由多个middleware构成,这里的middleware跟我之前已经形成“思维定势”的middleware不太一样,以前一说中间件,想到的是weblogic、jboss之类的application server,这里的middleware没有那么庞大,他们指的就是一些以特定逻辑来处理web request的函数块。

名词定义:

JSGI,JSGI对web application的定义,认为web application就是一个function,接受request参数,返回一个response对象,这是一个纯粹的、具有简洁美的概念,所谓function,就是封装具体功能,让外界只关注输入参数类型和返回结果。能够从这个高度看待web application,确实是搞高。JSGI中,定义application就是由多个模块化的middleware组成,这些middleware能够从外部配置。

Application,JSGI application,我们之前已经介绍,就是一个JavaScript函数,接受request,返回response对象,一个最简单的JSGI application应该看起来这个样子:

function(request) {

return {

status: 200,

headers: {},

body: [“Hello World!”]

};

}

 

在JSGI规范中,还定义了一个Application对象,其本身当然包含前面说的application功能,另外还有一些额外的方法、特性。后文所说的application对象,指的都是这个。

 

Middleware,我们指的是一个JSGI application,它能够包裹住另一个JSGI application。request对象是否、如何传递给被包裹的JSGI application,完全由这个middleware来决定。

一个最简化的、不做任何操作的middleware,仅仅是将request作为参数传递给其包裹的内部application,并且返回结果,看起来应该是下面这个样子(nested是被middleware包裹的其他application,已经预先定义):

function(request) {

return nested(request);

}

 

Middleware Factory, 中间件工厂,姑且这么直译,就是一个JavaScript函数,其接受一个JSGI application作为参数,然后返回一个middleware function。这有点绕,代码看起来应该这个样子:

function(nested) {

return function(request) {

return nested(request);

};

}

 

这是一个简单的闭包(closure)。

Middleware Chain,每一个JSGI application,其内部都可能包裹着多个middleware函数,形成一个链。

The Application Object,前面说过了,很绕的,application 对象呢本身也还是JSGI application,但是其内部又包裹了middleware chain,当执行时,application对象就像一个proxy,调用middleware chain,将request传递给chain,并从middleware chain返回结果。

Application存在一个默认的构造函数:

var app = new Application();

不带参数调用构造函数,创建的这个application,其内部的middleware chain被初始化为unhandled()函数,只能在调用的时候抛出一个异常。

构造函数可以接受一个JSGI application作为参数输入,如:

var app = new Application(responder);

这构建的application对象,将使用responder()作为其内部的JSGI middleware chain。

configure()

Application 对象(前面通过构造函数创建的那个),有一个名为configure的方法,其接受一个或多个middleware factory(还记得啥是middleware factory么?),将其加入现有的middleware chain上,看一个例子:

app.configure(log, responder);

这将导致application的middleware chain为 log(responder(unhandled()))。

Middleware factories也可能给application添加属性或方法,帮助我们从外部配置middleware,下面我们会提及。

env()

Application 对象有一个env方法,其接受一个字符串参数,返回一个Application对象,其具有和原Application同样的middleware chain,但其后续通过configure()配置添加的middleware不会影响原来的application——类似于fork的概念,嗯? 父进程、子进程。

var development = app.env(“development”);

原文档中,此处给出了env()的例子,进一步进行说明,这里不列出了。需要注意,使用同样的字符串参数,对某application对象做多次env()调用,只会返回同一个application。

Middleware Factories——前面不是介绍过了么?这章节咋安排的?

Middleware factories一般来说,可以接受两个参数:

  1. application的当前JSGI middleware chain
  2. application对象本身

一个middleware factory通常会返回一个middleware function,一般这个middleware function会wrapJSGI middleware chain——第一个参数。

另外,middleware factory可能修改第二个参数(application)的属性、方法(一般都是添加),好让外部通过这些属性、方法,实现配置的目的。

例子:

function Logger(nested, app) {

var enabled = false;

app.enabledLogging = function() {

enabled = true;

}

 

return function(request) {

if (enabled) {

log(request);

}

return nested(request);

}

}

 

我们来使用这个middleware:

var app = new Application();

// ...

app.configure(Logger);

app.enableLogging();

 

一般来说,模块(module)会将JSGI application以app名称导出,middleware factory的导出名称会是middleware.

对于一个application方法,其接受的参数是JSGI app或者middleware factory,如果我们调用时,传入的参数是一个字符串,那这个字符串会被当做是module id,Ringo会先require()这个module id,然后使用这个模块导出的app或者middleware属性。

 

思考: application 就是 middleware?

middleware factory就是返回application或者说middleware的方法,其实现实现wrap middleware chain,并可能给application配置一些用来做外部配置的hook。

Leave Comment