Nova API服务 之 处理HTTP请求的流程

一、回顾

1、Nova API服务的主要功能都在osapi_compute_app_v2应用程序中实现。osapi_compute_app_v2应用程序对应的工

方法是APIRouter类的factory方法。APIRouter类的factory方法会返回一个APIRouter对象。当客户端发送HTTP请

求的时候,会调用APIRouter对象的__call__方法。

2、APIRouter继承自Router类,__call__方法便定义在Router类中。Router类的__call__方法的定义是self.router

象,最终会返回资源对应的Controller对象。

3、servers资源的Controller对象是一个wsgi.Resource对象。因此。当客户端发送HTTP请求后,Nova API服务最终

会调用wsgi.Resource对象的__call__方法。 /nova/api/openstack/wsgi.py

def create_resource(ext_mgr):
    return wsgi.Resource(Controller(ext_mgr))

二、wsgi.Resource类的初始化方法和__call__方法的定义

1、初始化方法

wsgi.Resource类的初始化方法定义如下:

def __init__(self, controller, action_peek = None, inherits = None,
	#底层Controller对象
	self.controller = controller
    # 反序列化对象
	default_deserializers = dict(json = JSONDeserializer)
	default_deserializers.update(deserializers)

	self.default_deserializers = default_deserializers
	# 序列化对象
	self.default_serializers = dict(json = JSONDictSerializer)
	......
 Resource类是在资源的底层Controller类的基础上,添加了 序列化和反序列化的功能。

序列化:是指将XML或JSON格式的数据转化成字符串格式,以便于在网络间传输

反序列化:将字符串数格式的数据转换为XML或JSON数据格式,以便于显示和处理。 所以,在Resource类中通过两个

成员变量default_deserializers和default_serializers来分别实现数据的反序列化和序列化。 

2、__call__方法

Resource类的__call__方法定义如下:

@webob.dec.wsgify(RequestClass=Request) //wsgify装饰器
def __call__(self, request):


    # Identify the action, its arguments, and the requested
    # content type
	#获取客户端传入的HTTP请求参数
    action_args = self.get_action_args(request.environ)
	#获取HTTP请求的操作名:post put delete get
    action = action_args.pop('action', None)
	#获取客户端传入的报文
	#content_type:客户端传入的报文格式  body:客户端传入的报文内容
    content_type, body = self.get_body(request)
	#获取服务器返回的报文类型
    accept = request.best_match_content_type()

	#处理HTTP请求
    return self._process_stack(request, action, action_args,
                               content_type, body, accept)
可以看出,__call__方法最后调用了_process_stack方法。

_process_stack方法的定义如下:

def _process_stack(self, request, action, action_args,
                       content_type, body, accept):

        #获取处理HTTP请求的方法
        try:
            meth, extensions = self.get_method(request, action,
                                               content_type, body)
        except (AttributeError, TypeError):
            return Fault(webob.exc.HTTPNotFound())
        except KeyError as ex:
            msg = _("There is no such action: %s") % ex.args[0]
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))
        except exception.MalformedRequestBody:
            msg = _("Malformed request body")
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))
		
        if body:
            msg = _("Action: '%(action)s', calling method: %(meth)s, body: "
                    "%(body)s") % {'action': action,
                                   'body': six.text_type(body, 'utf-8'),
                                   'meth': str(meth)}
            LOG.debug(strutils.mask_password(msg))
        else:
            LOG.debug("Calling method '%(meth)s'",
                      {'meth': str(meth)})

        #反序列化客户端传入的消息
        try:
            contents = {}
            if self._should_have_body(request): #如果传入客户端消息
                # allow empty body with PUT and POST
                if request.content_length == 0:
                    contents = {'body': None}
                else:
                    contents = self.deserialize(meth, content_type, body)
        except exception.InvalidContentType:
            msg = _("Unsupported Content-Type")
            return Fault(webob.exc.HTTPUnsupportedMediaType(explanation=msg))
        except exception.MalformedRequestBody:
            msg = _("Malformed request body")
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))

        #更新请求的参数,将传入的消息体内容添加到action_args中
        action_args.update(contents)
		#获取客户端所属的项目ID
        project_id = action_args.pop("project_id", None)
        context = request.environ.get('nova.context')
		#检查客户端请求是否合法
        if (context and project_id and (project_id != context.project_id)):
            msg = _("Malformed request URL: URL's project_id '%(project_id)s'"
                    " doesn't match Context's project_id"
                    " '%(context_project_id)s'") % \
                    {'project_id': project_id,
                     'context_project_id': context.project_id}
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))

        #执行HTTP请求的前向扩展方法
        response, post = self.pre_process_extensions(extensions,
                                                     request, action_args)
		#前向扩展方法没有返回response,说明需要对请求进行进一步处理
        if not response:
            try:
                with ResourceExceptionHandler():
					#执行底层Controller对象中 处理HTTP请求 的方法
                    action_result = self.dispatch(meth, request, action_args)
            except Fault as ex:
                response = ex
		#前向扩展方法没有返回response,处理底层controller对象 方法返回的结果
        if not response:
            resp_obj = None
			#如果controller对象方法返回结果为字典,则封装成ResponseObject对象
            if type(action_result) is dict or action_result is None:
                resp_obj = ResponseObject(action_result)
			#如果controller对象方法返回结果为ResponseObject对象
            elif isinstance(action_result, ResponseObject):
                resp_obj = action_result
			#否则认为返回的结果是response对象
            else:
                response = action_result

            #如果controller对象方法没有返回response对象,则继续处理resp_obj对象
            if resp_obj:
                #获取controller对象方法 指定的序列化对象
                serializers = getattr(meth, 'wsgi_serializers', {})
				#绑定序列化对象
                resp_obj._bind_method_serializers(serializers)
				#获取controller对象方法默认的HTTP code 
                if hasattr(meth, 'wsgi_code'):
                    resp_obj._default_code = meth.wsgi_code
				#获取accept报文格式下的序列化方法
				#如果controller对象方法未指定序列化方法,则使用默认的序列化方法
                resp_obj.preserialize(accept, self.default_serializers)

                #执行HTTP请求的后向扩展方法
                response = self.post_process_extensions(post, resp_obj,
                                                        request, action_args)
			#如果后向方法没有返回response对象
            if resp_obj and not response:
				#将controller对象方法返回结果 序列化
                response = resp_obj.serialize(request, accept,
                                              self.default_serializers)

        if hasattr(response, 'headers'):

            for hdr, val in response.headers.items():
                # Headers must be utf-8 strings
                response.headers[hdr] = utils.utf8(str(val))

            if not request.api_version_request.is_null():
                response.headers[API_VERSION_REQUEST_HEADER] = \
                    request.api_version_request.get_string()
                response.headers['Vary'] = API_VERSION_REQUEST_HEADER

        return response
(1)、获取HTTP请求的参数,调用deserialize方法将 HTTP请求的消息体反序列化成 字典对象。并且通过检查项目ID

来验证客户是否有执行HTTP请求的权限。

(2)、调用pre_process_extensions方法执行HTTP请求的前向扩展方法。前向扩展方法是为了便于二次开发预留的接

口。在Nova API处理HTTP请求的时候,会首先执行前向扩展方法,然后再执行底层Controller对象中的处理方法。

pre_process_extensions方法返回一个post对象,它是HTTP请求后向扩展方法的列表。后向扩展方法也是预留的二次

开发接口,会在底层的Controller对象的处理方法执行之后执行。

(3)、通过调用dispatch方法运行底层Controller对象的处理方法。底层Controller对象处理方法返回一个字典。

resp_obj = ResponseObject(action_result)将返回的结果封装成ResponseObject对象。

(4)、对ResponseObject对象进行一些配置,需要配置的属性有:序列化对象、默认的HTTP CODE。

(5)、ResponseObject对象的序列化对象和HTTP Code是在底层Controller对象的处理方法中指定。底层Controller对

象的每个处理方法都可以通过装饰器指定序列化对象、反序列化对象和HTTP Code。例如:


指定了index方法的XML序列化对象为MinimalServersTemplate对象,如下代码片段:


指定了create方法的XML序列化对象为 FullServersTemplate对象,xml反序列化对象为CreateDeserializer,默认的

HTTP Code为202。当HTTP请求处理成功时,Nova API服务器会向客户端返回202 的HTTP Code。

(6)、HTTP请求的后向扩展方法,将ResponseObject对象序列化。

总结:由于前向扩展方法和后向扩展方法在Nova中没有使用过,因此HTTP请求的核心工作依然在底层Controller类的

处理方法中定义。_process_stack方法主要是完成了数据的序列化和反序列化工作


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值