最近用到一个 gem 叫做 rest-client-component,它的主要作用就是让 restclient 能够添加中间件,从而使得在发出 http 请求之前或者在收到 http 应答之后对请求和应答做相关处理。但是在使用的时候,我发现它所添加的中间件是 rack 的中间件。这就引起了我的好奇。
rack 本身是定义的 web server 与 web framework 之间的接口,那么在我印象中 rack 相关的中间件也一定是用于服务端的,这怎么可以用于客户端呢?于是就仔细研究了相关资料和源代码,才发现自己的之前的“认为“过于肤浅。
我们首先来看一个图,这个图描述了一次对基于 rack 的 web app 的请求应答的过程图:
从这个图中我们可以看到当一个 http 请求来临的时候,这个请求中的相关信息通过 server 和 rack handler 转换为了 env 中相关的内容,然后再经过 rack middleware 相关处理,最后经由 rack adapter 变为 web app 能够识别的信息。当不存在 rack middleware 的时候,那么传入 web app 的 env 的本身其实就是 client 发出的 request,他们之间的差别只是格式不同,但所表达的信息是一样的(当然这里说法并不准确,后面有解释)。
同样,当 web app 处理请求完成后,其处理的结果由 rack adapter 转换成了 [status, headers, [body]] 的形式,然后经过 rack middleware 处理,最后通过 rack handler 和 server 的处理,将这些信息变成一个 response 返回给客户端。那么当不存在 middleware 的时候,web app 返回的 [status, headers, [body]] 本质上与最后返回给客户端的 response 是一样的。
所以我们就可以将 env 和 [status, headers, [body]] 与 request 和 response 等同起来。那么从这里我们就可以看出来,rack middle 本身的作用其实就是处理 request 和 response。rack middleware 的作用就像这篇文章说的:
The fundamental idea behind Rack middleware is – come between the calling client and the server, process the HTTP request before sending it to the server, and processing the HTTP response before returning it to the client.
这句话改成这样或许更准确一点
The fundamental idea behind Rack middleware is – come between the calling client and the server, process the HTTP request before sending it to the
serverweb application
, and processing the HTTP response before returning it to the client.
这句话说的是 rack middleware 本身出现的目的。但是我们可以将 rack middleware 理解得更加广一点。rack middleware 的作用是处理 request 和 response 的,它就像是一根电线,电线里面有火线和零线,而火线和零线分别对应这里的 request 的通道和 response 的通道,而每个完整的请求应答信息 (env 与 [status, header, [body]]) 就像电流。就如下图一样:(当然这个电线也可能会短路。。)
电线可以加入进电流通路的任何地方。那么同样的 middleware 为什么不能够加入到 http 请求应答路径所经过的任何地方呢?
客户端本身就是每一个 http 请求应答所会经过的必经之路,那么当然 rack middleware 也就能够放在客户端使用了。当然由于 rack middleware 处理的 request 和 response 的格式并不一样,所以我们就要自己写格式相关的代码。当 rack middleware 放在客户端的时候,其结构就如下图 (以 restclient 为例):
当然,由于没有了 rack 的支持,client 还要实现 middleware 栈的调用机制。
上面说当不存在 middleware 的时候,request 内容等同于 env。其实现实情况不一定,因为服务器也可能会对 request 做一些处理(比如 webrick 可以调用一些 callback),当然这并不损 env 代表一个 request 的事实。
从 rack middleware 这个问题,我突然意识到,任何东西我们都要尽量要去掌握它的本质,而不要只看到它的表面或者它出现的背景。不然我们很可能无法广泛灵活的去应用这些东西。突然感觉我们日常生活中其实处处存在这个道理。大到核能的应用,核能最早出现也是用于战争,但是理解了它的本质,它也能用于人类的生产生活。小到日常生活中,我们会用凳子当做梯子使用,用废弃的饮料瓶作为花瓶。所以既然在生活中能够将一种东西按照他本身的特性去使用它,而并不只是局限于它出现的直接目的去使用它。那么在技术中,我们或许也可以视情况用这种思维去使用它们,或许有不同的惊喜。
还有就是我是菜鸟,请大家多多指教:)