aliyunsdkcore源码简析

本文剖析了aliyunsdkcore源码,介绍了异常处理机制、请求对象构造、客户端类实现及HTTP响应处理等内容,为开发者理解阿里云SDK工作原理提供了帮助。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

aliyunsdkcore源码

一、目录结构

aliyunsdkcore
    --acs_exception        # 异常相关
        --__init__.py        
        --error_code.py        # 定义了error的id名
        --error_msg.py        # 定义了部分和error_code对应的描述信息
        --error_type.py        # 定义了四种错误类型:clint、server、throttling、unknown
        --exceptions.py        # 定义了ClintException、ServerException
    --auth                # 认证相关
    --http                # http连接相关
        --__init__.py
        --format_type.py    # 定义可接受文档类型(xml、json、raw)及相关方法
        --http_request.py    # 定义HttpRequest
        --http_response.py  # 定义HttpResponse
        --method_type.py    # 定义了6种基本请求方法
        --protocol_type.py    # 定义http和https
    --profile                # 解析产品及endpoint的文件                        
    --utils                    # 扩展的工具和方法
        --__init__.py
        --parameter_helper.py        # 定义了获取uuid,时间等方法
    --__init__.py
    --client.py            # 定义了ACSclient类
    --endpoints.xml        
    --request.py        # 定义了Acs请求类

二、源码简析

1、异常部分

​ aliyunsdkcore/acs_exception目录下主要定义了基本的Exception的ID、提示信息、类型和两个异常类(ClintException、ServerException)。

​ 以下是ClintException的源码:

class ClientException(Exception):

    def __init__(self, code, msg):
        Exception.__init__(self)
        self.__error_type = error_type.ERROR_TYPE_CLIENT # 设置为error_type中的ERROR_TYPE_CLIENT类型
        self.message = msg    # 初始化错误信息
        self.error_code = code # 初始化错误代码
    
    # 重写__str__(), x.__str__() <==> str(x)
    def __str__(self):
        return "%s %s" % (
            self.error_code,
            self.message,
        )
    # 定义属性设置、获取方法
    def set_error_code(self, code):
        self.error_code = code
    def set_error_msg(self, msg):
        self.message = msg
    def get_error_type(self):
        return self.__error_type
    def get_error_code(self):
        return self.error_code
    def get_error_msg(self):
        return self.message

​ ServerException类比ClientException多了http状态码、request_id等属性及相应方法,不做赘述。

2、Request.py
设置默认请求类型
_default_protocol_type = protocol_type.HTTP

def set_default_protocol_type(user_protocol_type):
    global _default_protocol_type

    # 设置默认请求类型,如果用户提供的参数不是http或https就抛出异常
    if user_protocol_type == protocol_type.HTTP or user_protocol_type == protocol_type.HTTPS:
        _default_protocol_type = user_protocol_type
    else:
        raise exceptions.ClientException(
            error_code.SDK_INVALID_PARAMS, 
            "Invalid 'protocol_type', should be 'http' or 'https'"
        )
请求对象

aliyunsdkcore/request.py中定义了四个类:

  • AcsRequest——抽象类,封装了通用的属性及方法
  • RpcRequest——继承AcsRequest,Rpc风格的请求对象
  • RoaRequest——继承AcsRequest,Roa风格的请求对象
  • OssRequest——继承AcsRequest,Oss风格的请求对象
  • CommonRequest——继承了RpcRequest和RoaRequest

笔者阅码有限,目前只知道阿里云的aliyunsdkecs模块的Request对象基本继承自RpcRequest,aliyunsdkros模块的Request对象则继承自RoaRequest,这一点在两种产品的API风格中就可窥见一斑,至于OssRequest和CommonRequest还没见到过,若读者大大知道,还望不吝赐教,哈哈!

AcsRequest
__ init __(...)

AcsRequest 的__ init __(...) 的源码。

class AcsRequest:
    """
    Acs request base class. This class wraps up common parameters for a request.
    """
    __metaclass__ = abc.ABCMeta

    def __init__(self, product, version=None,
                 action_name=None,
                 location_service_code=None,
                 location_endpoint_type='openAPI',
                 accept_format=None,
                 protocol_type=None,
                 method=None):

        self._version = version        # 版本
        self._product = product        # 产品名
        self._action_name = action_name      # 操作名
        self._protocol_type = protocol_type    # 协议类型
        if self._protocol_type is None:
            self._protocol_type = _default_protocol_type

        self._accept_format = accept_format    
        self._params = {}        # 参数 dict
        self._method = method    # 请求方法
        self._header = {}        # 请求头
        self._body_params = {}    # body体参数
        self._uri_pattern = None# uri模板
        self._uri_params = None # uri需要的参数
        self._content = None    # 内容
        self._location_service_code = location_service_code 
        self._location_endpoint_type = location_endpoint_type
        self.add_header('x-sdk-invoke-type', 'normal')

还有一些相关属性的设置、获取方法,以及三个抽象方法:

    @abc.abstractmethod
    def get_style(self):
        pass

    @abc.abstractmethod
    def get_url(self, region_id, ak, secret):
        pass

    @abc.abstractmethod
    def get_signed_header(self, region_id, ak, secret):
        pass
3、client.py

此处定义了一个AcsClient类,__ init __(...)如下:

def __init__(
    self,
    ak=None,                # 用户key
    secret=None,            # 用户secret
    region_id="cn-hangzhou",# 地区id
    auto_retry=True,         # 连接失败自动重连
    max_retry_time=3,        # 最多重连次数
    user_agent=None,        # 用户代理
    port=80,                # 连接端口
    timeout=DEFAULT_SDK_CONNECTION_TIMEOUT_IN_SECONDS,    # 超时:默认10秒
    public_key_id=None,        
    private_key=None,
    session_period=3600,    # session过期时间
    credential=None,        # 证书
    debug=False):            # 是否处于debug模式

    self.__max_retry_num = max_retry_time
    self.__auto_retry = auto_retry
    self.__ak = ak
    self.__secret = secret
    self.__region_id = region_id
    self.__user_agent = user_agent
    self._port = port
    self._location_service = LocationService(self, timeout=timeout)
    self._timeout = timeout
    # if true, do_action() will throw a ClientException that contains URL
    self._url_test_flag = False
    credential = {
        'ak': ak,
        'secret': secret,
        'public_key_id': public_key_id,
        'private_key': private_key,
        'session_period': session_period,
        'credential': credential,
    }
    self._signer = SignerFactory.get_signer(credential, region_id, self.implementation_of_do_action, debug)
get_response()

常用的一个方法是get_response()

def get_response(self, acs_request):
    return self.implementation_of_do_action(acs_request)    # 调用implementation_of_do_action()
    
    
def implementation_of_do_action(self, request, signer=None):
      # 判断是否是AcsRequest,不是则抛出异常
      if not isinstance(request, AcsRequest):
        raise ClientException(
              error_code.SDK_INVALID_REQUEST,
              error_msg.get_msg('SDK_INVALID_REQUEST'))

    # add core version
    core_version = __import__('aliyunsdkcore').__version__
    request.add_header('x-sdk-core-version', core_version)

    # 如果是CommonRequest,则Requeste标记成相应风格
    if isinstance(request, CommonRequest):
      request.trans_to_acs_request()

    # 设置接收端并创建Response
    endpoint = self._resolve_endpoint(request)
    http_response = self._make_http_response(endpoint, request, signer)
       if self._url_test_flag:
        raise ClientException("URLTestFlagIsSet", http_response.get_url())

    # Do the actual network thing 请求
    try:
        status, headers, body = http_response.get_response_object() # 调用get_response_object
        return status, headers, body
    except IOError as e:
        raise ClientException(
            error_code.SDK_SERVER_UNREACHABLE,
            error_msg.get_msg('SDK_SERVER_UNREACHABLE') + ': ' + str(e))
4、http
HTTPResponse
get_response_object()

上文中的get_response_object()是aliyunsdkcorehttphttp_response.py中HttpResponse的方法

def get_response_object(self):
      # 根据是否提供ssl证书,调用使用相应协议的方法
      if self.get_ssl_enabled():
        return self.get_https_response_object()
     else:
        return self.get_http_response_object()

# http
def get_http_response(self):
      # 端口 未指定则默认80
    if self.__port is None or self.__port == "":
        self.__port = 80
        try:
              # 创建HTTPConnection对象
            self.__connection = httplib.HTTPConnection(
                  self.get_host(), self.__port, timeout=self._timeout)
            # 连接
            self.__connection.connect()
            # 请求
            self.__connection.request(
                  method=self.get_method(),
                  url=self.get_url(),
                 body=self.get_body(),
                 headers=self.get_headers())
            # 接收
            response = self.__connection.getresponse()
            # 返回status,headers,body
            return response.status, response.getheaders(), response.read() 
        finally:
              # 关闭连接
              self.__close_connection()

https则默认使用443端口,httplib.HTTPSConnection()创建连接对象。

do_action_with_exception()

另外常用的是do_action_with_exception(),是已经废弃的do_action()的升级版,自动解析response。

def do_action_with_exception(self, acs_request):
    # set server response format as json, because thie function will
    # parse the response so which format doesn't matter
    acs_request.set_accept_format('JSON')

    status, headers, body = self.implementation_of_do_action(acs_request)

    request_id = None
    
    # 尝试获取request
    try:
        body_obj = json.loads(body)
        request_id = body_obj.get('RequestId')
    except ValueError or TypeError or AttributeError:
            # in case the response body is not a json string, return the raw
            # data instead
            pass
    # 判断请求状态码,如果请求错误,指定请求ID、错误代码、错误信息,抛出异常    
    if status < httplib.OK or status >= httplib.MULTIPLE_CHOICES:
        server_error_code, server_error_message = self._parse_error_info_from_response_body(
                body)
        raise ServerException(
                server_error_code,
                server_error_message,
                http_status=status,
                request_id=request_id)

        return body
_parse_error_info_from_response_body()

AcsRequest还提供了一个解析错误信息的类方法:

@staticmethod
def _parse_error_info_from_response_body(response_body):
    
    # 以json格式解析
    try:
        body_obj = json.loads(response_body)
        if 'Code' in body_obj and 'Message' in body_obj:
            return body_obj['Code'], body_obj['Message']
        else:
            return (
                error_code.SDK_UNKNOWN_SERVER_ERROR,
                error_msg.get_msg('SDK_UNKNOWN_SERVER_ERROR'))
    # 不能解析则设置错误信息类型为SDK_UNKNOWN_SERVER_ERROR 未知错误
    except ValueError:
        # failed to parse body as json format
        return (error_code.SDK_UNKNOWN_SERVER_ERROR,
                error_msg.get_msg('SDK_UNKNOWN_SERVER_ERROR'))

以上大致就是简单的一些分析,其中auth部分和profile部分分别提供认证和请求目标点等服务,也不做具体分析了。

仅作学习之余的笔记,如有误点还望大神宥谅则个,并在评论区留下正解,不胜感激。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值