花了两个星期,我终于把 WSGI 整明白了 (4)

经过了 PasteDeploy 的路由调度,我们找到了 nova.api.openstack.compute:APIRouterV21.factory 这个 application 的入口,看代码知道它其实返回了 APIRouterV21 类的一个实例。

WSGI规定 application 必须是一个 callable 的对象,函数、方法、类、实例,若是一个类实例,就要求这个实例所属的类实现 __call__ 的方法。

APIRouterV21 本身没有实现 __call__ ,但它的父类 Router实现了 __call__

我们知道,application 必须遵丛 WSGI 的规范

必须接收environ, start_response两个参数;

必须返回 「可迭代的对象」。

但从 Router 的 __call__ 代码来看,它并没有遵从这个规范,它不接收这两个参数,也不返回 response,而只是返回另一个 callable 的对象,就这样我们的视线被一次又一次的转移,但没有关系,这些__call__都是外衣,只要扒掉这些外衣,我们就能看到核心app。

而负责扒掉这层外衣的,就是其头上的装饰器 @webob.dec.wsgify ,wsgify 是一个类,其 __call__ 源码实现如下:

可以看出,wsgify 在这里,会将 req 这个原始请求(dict对象)封装成 Request 对象(就是规范1里提到的 environ)。然后会一层一层地往里地执行被wsgify装饰的函数(self._route), 得到最内部的核心application。

上面提到了规范1里的第一个参数,补充下第二个参数start_response,它是在哪定义并传入的呢?

其实这个无需我们操心,它是由 wsgi server 提供的,如果我们使用的是 wsgiref 库做为 server 的话。那这时的 start_response 就由 wsgiref 提供。

再回到 wsgify,它的作用主要是对 WSGI app 进行封装,简化wsgi app的定义与编写,它可以很方便的将一个 callable 的函数或对象,封装成一个 WSGI app。

上面,其实留下了一个问题,self._route(routes 中间件 RoutesMiddleware对象)是如何找到真正的 application呢?

带着这个问题,我们了解下 routes 是如何为我们实现第二次路由。

08. 第二次路由:中间件 routes 路由

在文章最开始处,我们给大家画了一张图。

这张图把一个 HTTP 请求粗略简单地划分为两个过程。但事实上,整个过程远比这个过程要复杂得多。

实际上在 WSGI Server 到 WSGI Application 这个过程中,我们加很多的功能(比如鉴权、URL路由),而这些功能的实现方式,我们称之为中间件。

中间件,对服务器而言,它是一个应用程序,是一个可调用对象, 有两个参数,返回一个可调用对象。而对应用程序而言,它是一个服务器,为应用程序提供了参数,并且调用了应用程序。

今天以URL路由为例,来讲讲中间件在实际生产中是如何起作用的。

当服务器拿到了客户端请求的URL,不同的URL需要交由不同的函数处理,这个功能叫做 URL Routing。

在 Nova 中是用 routes 这个库来实现对URL的的路由调度。接下来,我将从源代码处分析一下这个过程。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwppjj.html