在routes模块里有个中间件,叫 routes.middleware.RoutesMiddleware ,它将接受到的 url,自动调用 map.match()方法,对 url 进行路由匹配,并将匹配的结果存入request请求的环境变量['wsgiorg.routing_args'],最后会调用self._dispatch(dispatch返回真正的application)返回response,最后会将这个response返回给 WSGI Server。
这个中间件的原理,看起来是挺简单的。并没有很复杂的逻辑。
但是,我在阅读 routes 代码的时候,却发现了另一个令我困惑的点。
self._dispatch (也就上图中的self.app)函数里,我们看到了 app,controller 这几个很重要的字眼,其是否是我苦苦追寻的 application 对象呢?
要搞明白这个问题,只要看清 match 到是什么东西?
这个 match 对象 是在 RoutesMiddleware.__call__() 里塞进 req.environ 的,它是什么东西呢,我将其打印出来。
{'action': u'detail', 'controller': <nova.api.openstack.wsgi.ResourceV21 object at 0x667bad0>, 'project_id': u'2ac17c7c792d45eaa764c30bac37fad9'} {'action': u'index', 'controller': <nova.api.openstack.wsgi.ResourceV21 object at 0x6ec8910>, 'project_id': u'2ac17c7c792d45eaa764c30bac37fad9'} {'action': u'show', 'controller': <nova.api.openstack.wsgi.ResourceV21 object at 0x6ed9710>, 'project_id': u'2ac17c7c792d45eaa764c30bac37fad9', 'id': u'68323d9c-ebe5-499a-92e9-32fea900a892'}结果令人在失所望呀,这个 app 并不是我们要寻找的 Controller 对象。而是 nova.api.openstack.wsgi.ResourceV21 类的实例对象,说白了就是Resource 对象。
看到这里,我有心态有点要崩了,怎么还没到 Controller?OpenStack 框架的代码绕来绕去的,没有点耐心还真的很难读下去。
既然已经开了头,没办法还得硬着头皮继续读了下去。
终于我发现,在APIRouter初始化的时候,它会去注册所有的 Resource,同时将这些 Resource 交由 routes.Mapper 来管理、创建路由映射,所以上面提到的 routes.middleware.RoutesMiddleware 才能根据url通过 mapper.match 获取到相应的Resource。
从 Nova 代码中看出每个Resource 对应一个 Controller 对象,因为 Controller 对象本身就是对一种资源的操作集合。
通过日志的打印,可以发现 nova 管理的 Resource 对象有多么的多而杂
os-server-groups os-keypairs os-availability-zone remote-consoles os-simple-tenant-usage os-instance-actions os-migrations os-hypervisors diagnostics os-agents images os-fixed-ips os-networks os-security-groups os-security-groups os-security-group-rules flavors os-floating-ips-bulk os-console-auth-tokens os-baremetal-nodes os-cloudpipe os-server-external-events os-instance_usage_audit_log os-floating-ips os-security-group-default-rules os-tenant-networks os-certificates os-quota-class-sets os-floating-ip-pools os-floating-ip-dns entries os-aggregates os-fping os-server-password os-flavor-access consoles os-extra_specs os-interface os-services servers extensions metadata metadata limits ips os-cells versions tags migrations os-hosts os-virtual-interfaces os-assisted-volume-snapshots os-quota-sets os-volumes os-volumes_boot os-volume_attachments os-snapshots os-server-groups os-keypairs os-availability-zone remote-consoles os-simple-tenant-usage os-instance-actions os-migrations os-hypervisors diagnostics os-agents images os-fixed-ips os-networks os-security-groups os-security-groups os-security-group-rules flavors os-floating-ips-bulk os-console-auth-tokens os-baremetal-nodes os-cloudpipe os-server-external-events os-instance_usage_audit_log os-floating-ips os-security-group-default-rules os-tenant-networks os-certificates os-quota-class-sets os-floating-ip-pools os-floating-ip-dns entries os-aggregates os-fping os-server-password os-flavor-access consoles os-extra_specs os-interface os-services servers extensions metadata metadata limits ips os-cells versions tags migrations os-hosts os-virtual-interfaces os-assisted-volume-snapshots os-quota-sets os-volumes os-volumes_boot os-volume_attachments os-snapshots你一定很好奇,这路由是如何创建的吧,关键代码就是如下一行。如果你想要了解更多路由的创建过程,可以看一下这篇文章(Python Route总结),写得不错。
routes.mapper.connect("server", "/{project_id}/servers/list_vm_state", controller=self.resources['servers'], action='list_vm_state', conditions={'list_vm_state': 'GET'})历尽了千辛万苦,我终于找到了 Controller 对象,知道了请求发出后,wsgi server是如何根据url找到对应的Controller(根据routes.Mapper路由映射)。
但是很快,你又会问。对于一个资源的操作(action),有很多,比如新增,删除,更新等
不同的操作要执行Controller 里不同的函数。
如果是新增资源,就调用 create()
如果是删除资源,就调用 delete()
如果是更新资源,就调用 update()
那代码如何怎样知道要执行哪个函数呢?
以/servers/xxx/action请求为例,请求调用的函数实际包含在请求的body中。