調用APIRouter的 __call__函數 html
nova/wsgi.pyweb
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時,它還會被繼續調用,並返回它的處理結果。 json
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訪問。api
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。 app
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類的這個函數!ui
參考文檔:url