標籤:
3.2 調用APIRouter的 __call__函數
nova/wsgi.py
class Router(object):
def __init__(self, mapper): self.map = mapper self._router = routes.middleware.RoutesMiddleware(self._dispatch, self.map) @webob.dec.wsgify(RequestClass=Request) def __call__(self, req): return self._router @staticmethod @webob.dec.wsgify(RequestClass=Request) def _dispatch(req): match = req.environ[‘wsgiorg.routing_args‘][1] if not match: return webob.exc.HTTPNotFound() app = match[‘controller‘] return app
當osapi_compute_app_v2接收到HTTP請求時,根據類的繼承關係, 將調用nova.wsgi.Router.__call__函數,如上所示。查看一下webob.dec.wsgify 的源碼,發現如果函數返回的是wsgi app時,它還會被繼續調用,並返回它的處理結果。
3.2.1 self._router 為routes.middleware.RoutesMiddleware執行個體,所以會調用routes.middleware.RoutesMiddleware.__call__函數,該函數調用routes.mapper.routematch來擷取HTTP請求的URL所映射的controller等參數,以{"controller":Resource(Controller()), "action": funcname, "project_id": uuid, ...}的格式放在match中。並設定如下的environ變數,方便後面調用的self._dispatch訪問。
environ[‘wsgiorg.routing_args‘] = ((url), match) environ[‘routes.route‘] = route environ[‘routes.url‘] = url
最後調用self._dispatch()。 self._dispatch通過前面設定的environ[‘wsgiorg.routing_args‘]來找到url對應的controller,並返回該controller。
3.2.2 這裡的controller就是在APIRouter初始化中設定的controller,也就是使用相應Controller類初始化的Resource執行個體。所以接著調用nova.api.openstack.wsgi.Resource.__call__函數,該函數通過environ[‘wsgiorg.routing_args‘]擷取上面設定的match,該match有一個action屬性,它指定了所要調用Controller成員函數的名字,以及其它相關的調用參數。在我們定義Controller的成員函數時,一般需要通過nova.api.openstack.wsgi.{serializers, deserializers}來指定解釋body內容的模板,可以是xml或者json格式的。前面說過重定義nova.api.openstack.urlmap.URLMap的目的是為了判斷content_type。Resource接著在解析body時會參考content_type,然後調用相應的解析器進行body解析(如XMLDeserializer、JSONDeserializer),接著將解析出的參數更新進action_args,使用action_args來調用Controller成員函數,即最終的http請求處理函數。最後將執行結果使用指定的序列化器序列化,並返回結果。
3.2.3 這裡特別說明一下對常見RESTful請求之外的action請求的處理。以/servers/xxx/action請求為例,請求調用的函數實際包含在請求的body中。經過routes.middleware.RoutesMiddleware的__call__函數解析後,此時即將調用的Resource已經確定為哪個模組中的Controller所構建的Resource,而action參數為"action",接下來在Resource的__call__函數裡面會因為action=="action"從而開始解析body的內容,找出Controller中所對應的方法。Controller在構建的過程中會由於MetaClass的影響將其所有action類型的方法填入一個字典中,key由每個_action_xxx方法前的@wsgi.action(‘xxx‘)裝飾函數給出,value為每個_action_xxx方法的名字(從中可以看出規律,在body裡面請求的方法名前加上_aciton_即為Controller中對應調用的方法)。之後在使用Controller構建Resource對象的過程中會向Resource註冊該Controller的這個字典中的內容。這樣,只需在請求的body中給出調用方法的key,然後就可以找到這個key所映射的方法,最後在Resource的__call__函數中會調用Controller類的這個函數!
參考文檔:
http://www.it165.net/pro/html/201407/17020.html
nova-api源碼分析(APP的調用)