123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- # coding=utf-8
- import hashlib
- import inspect
- import time
- from collections import OrderedDict
- from urlparse import urljoin
- import typing
- import requests
- import logging
- import simplejson as json
- from simplejson import JSONDecodeError
- from library.jdopen.client.api.base import BaseJdOpenAPI
- from library.jdopen.constants import JdOpenResultCode
- from library.jdopen.exceptions import JdOpenException
- if typing.TYPE_CHECKING:
- from requests import Response
- logger = logging.getLogger(__name__)
- class JdOpenBaseClient(object):
- API_BASE_URL = ""
- def __new__(cls, *args, **kwargs):
- self = super(JdOpenBaseClient, cls).__new__(cls)
- apis = inspect.getmembers(self, lambda x: inspect.isclass(x) and issubclass(x, BaseJdOpenAPI))
- for apiName, apiClient in apis:
- setattr(self, apiName, apiClient(self))
- return self
- def __init__(self, accessKey, secretKey, timeout=None, auto_retry=True):
- self._accessKey = accessKey
- self._secretKey = secretKey
- self._timeout = timeout
- self._auto_retry = auto_retry
- @staticmethod
- def _decode_result(res): # type:(Response) -> typing.Optional[dict, str]
- """
- 解析request返回的结果
- """
- try:
- result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False)
- except (TypeError, ValueError, JSONDecodeError):
- logger.debug(u'错误的解析结构', exc_info=True)
- return res
- return result
- def calc_token(self, timestamp, path=None, body=None):
- data = OrderedDict()
- data["secretKey"] = self._secretKey
- data["timestamp"] = timestamp
- if path:
- data["path"] = path
- if body is not None:
- if isinstance(body, dict):
- data["body"] = json.dumps(body, separators=(",", ":"))
- else:
- data["body"] = body
- s = '&'.join([u'{}={}'.format(k, v) for k, v in data.items()])
- s = s.encode('utf-8')
- token = hashlib.sha1(s).hexdigest().upper()
- return token
- def _request(self, method, path, **kwargs):
- # 修补url
- logger.info("[{} send request], method = {}, path = {}, data = {}".format(self.__class__.__name__, method, path, kwargs))
- urlBase = kwargs.pop("urlBase", self.API_BASE_URL)
- url = urljoin(urlBase, path)
- # 修补data数据
- if isinstance(kwargs.get("data", ""), dict):
- data = kwargs.pop("data")
- kwargs['data'] = json.dumps(data, separators=(',', ':'))
- # 修补请求头
- timestamp = kwargs.pop("timestamp", str(int(time.time())))
- headers = {
- "Content-Type": "application/json",
- "accessKey": self._accessKey,
- "timestamp": timestamp,
- "token": self.calc_token(timestamp, path, body=kwargs.get("data", None))
- }
- kwargs.setdefault("params", {})
- kwargs.setdefault("timeout", self._timeout)
- callback = kwargs.pop("callback", None)
- with requests.sessions.Session() as _session:
- res = _session.request(
- method=method,
- url=url,
- headers=headers,
- **kwargs
- )
- try:
- res.raise_for_status()
- except requests.RequestException as rre:
- logger.info("[{} send request] error! status code = {}, error = {}".format(self.__class__.__name__, res.status_code, rre))
- raise JdOpenException(
- errCode='HTTP{}'.format(res.status_code),
- errMsg=rre.message,
- client=self,
- request=rre.request,
- response=rre.response
- )
- return self._handle_result(
- res, method, url, callback, **kwargs
- )
- def _handle_result(self, res, method, url, callback, **kwargs):
- """
- 主要用户重试
- """
- result = self._decode_result(res)
- logger.info("[{} handle_result] result = {}".format(self.__class__.__name__, result))
- if "result" not in result:
- return result
- # 正常请求
- if result["result"] == JdOpenResultCode.SUCCESS:
- return callback(result) if callback else result
- # 异常请求
- error = result["error"]
- raise JdOpenException(
- errCode=error.get("errorCode", ''),
- errMsg=error.get("errorMsg", ''),
- client=self,
- request=res.request,
- response=res
- )
- def get(self, url, **kwargs):
- return self._request("get", url, **kwargs)
- def post(self, url, **kwargs):
- return self._request("post", url, **kwargs)
|