123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- # -*- coding: utf-8 -*-
- '''
- Created on 2018-9-17
- @author: xiaoxuan.lp
- '''
- try: import http.client
- except ImportError:
- import http.client as httplib
- import urllib.request, urllib.parse, urllib.error
- import time
- import hashlib
- import json
- import dingtalk
- import itertools
- import mimetypes
- import hmac
- import base64
- '''
- 定义一些系统变量
- '''
- SYSTEM_GENERATE_VERSION = "taobao-sdk-python-dynamicVersionNo"
- P_APPKEY = "app_key"
- P_API = "method"
- P_ACCESS_TOKEN = "access_token"
- P_VERSION = "v"
- P_FORMAT = "format"
- P_TIMESTAMP = "timestamp"
- P_SIGN = "sign"
- P_SIGN_METHOD = "sign_method"
- P_PARTNER_ID = "partner_id"
- P_CODE = 'errcode'
- P_MSG = 'errmsg'
- def sign(secret, parameters):
- #===========================================================================
- # '''签名方法
- # @param secret: 签名需要的密钥
- # @param parameters: 支持字典和string两种
- # '''
- #===========================================================================
- # 如果parameters 是字典类的话
- if hasattr(parameters, "items"):
- keys = list(parameters.keys())
- keys.sort()
-
- parameters = "%s%s%s" % (secret,
- str().join('%s%s' % (key, parameters[key]) for key in keys),
- secret)
- sign = hashlib.md5(parameters.encode("utf-8")).hexdigest().upper()
- return sign
- def mixStr(pstr):
- if(isinstance(pstr, str)):
- return pstr
- elif(isinstance(pstr, str)):
- return pstr.encode('utf-8')
- else:
- return str(pstr)
-
- class FileItem(object):
- def __init__(self,filename=None,content=None):
- self.filename = filename
- self.content = content
- class MultiPartForm(object):
- """Accumulate the data to be used when posting a form."""
- def __init__(self):
- self.form_fields = []
- self.files = []
- self.boundary = "PYTHON_SDK_BOUNDARY"
- return
-
- def get_content_type(self):
- return 'multipart/form-data;charset=UTF-8; boundary=%s' % self.boundary
- def add_field(self, name, value):
- """Add a simple field to the form data."""
- self.form_fields.append((name, str(value)))
- return
- def add_file(self, fieldname, filename, fileHandle, mimetype=None):
- """Add a file to be uploaded."""
- body = fileHandle.read()
- if mimetype is None:
- mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
- self.files.append((mixStr(fieldname), mixStr(filename), mixStr(mimetype), mixStr(body)))
- return
-
- def __str__(self):
- """Return a string representing the form data, including attached files."""
- # Build a list of lists, each containing "lines" of the
- # request. Each part is separated by a boundary string.
- # Once the list is built, return a string where each
- # line is separated by '\r\n'.
- parts = []
- part_boundary = '--' + self.boundary
-
- # Add the form fields
- parts.extend(
- [ part_boundary,
- 'Content-Disposition: form-data; name="%s"' % name,
- 'Content-Type: text/plain; charset=UTF-8',
- '',
- value,
- ]
- for name, value in self.form_fields
- )
-
- # Add the files to upload
- parts.extend(
- [ part_boundary,
- 'Content-Disposition: form-data; name="%s"; filename="%s"' % \
- (field_name, filename),
- 'Content-Type: %s' % content_type,
- 'Content-Transfer-Encoding: binary',
- '',
- body,
- ]
- for field_name, filename, content_type, body in self.files
- )
-
- # Flatten the list and add closing boundary marker,
- # then return CR+LF separated data
- flattened = list(itertools.chain(*parts))
- flattened.append('--' + self.boundary + '--')
- flattened.append('')
- return '\r\n'.join(flattened)
- class TopException(Exception):
- #===========================================================================
- # 业务异常类
- #===========================================================================
- def __init__(self):
- self.errcode = None
- self.errmsg = None
- self.application_host = None
- self.service_host = None
-
- def __str__(self, *args, **kwargs):
- sb = "errcode=" + mixStr(self.errcode) +\
- " errmsg=" + mixStr(self.errmsg) +\
- " application_host=" + mixStr(self.application_host) +\
- " service_host=" + mixStr(self.service_host)
- return sb
-
- class RequestException(Exception):
- #===========================================================================
- # 请求连接异常类
- #===========================================================================
- pass
- class RestApi(object):
- #===========================================================================
- # Rest api的基类
- #===========================================================================
-
- def __init__(self, url=None):
- #=======================================================================
- # 初始化基类
- # Args @param domain: 请求的域名或者ip
- # @param port: 请求的端口
- #=======================================================================
- if(url == None):
- raise RequestException("domain must not be empty.")
- if(url.find('http://') >= 0):
- self.__port = 80
- pathUrl = url.replace('http://','')
- elif(url.find('https://') >= 0):
- self.__port = 443
- pathUrl = url.replace('https://','')
- else:
- raise RequestException("http protocol is not validate.")
-
- index = pathUrl.find('/')
- if(index > 0):
- self.__domain = pathUrl[0:index]
- self.__path = pathUrl[index:]
- else:
- self.__domain = pathUrl
- self.__path = ''
- # print("domain:" + self.__domain + ",path:" + self.__path + ",port:" + str(self.__port))
-
- def get_request_header(self):
- return {
- 'Content-type': 'application/json;charset=UTF-8',
- "Cache-Control": "no-cache",
- "Connection": "Keep-Alive",
- }
- def getHttpMethod(self):
- return "GET"
-
- def getapiname(self):
- return ""
-
- def getMultipartParas(self):
- return [];
- def getTranslateParas(self):
- return {};
-
- def _check_requst(self):
- pass
-
- def getResponse(self, authrize='',accessKey='',accessSecret='',suiteTicket='',corpId='', timeout=30):
- #=======================================================================
- # 获取response结果
- #=======================================================================
- if(self.__port == 443):
- connection = http.client.HTTPSConnection(self.__domain, self.__port, None, None, timeout)
- else:
- connection = http.client.HTTPConnection(self.__domain, self.__port, timeout)
- sys_parameters = {
- P_PARTNER_ID: SYSTEM_GENERATE_VERSION,
- }
- if authrize is not None:
- sys_parameters[P_ACCESS_TOKEN] = authrize
- application_parameter = self.getApplicationParameters()
- sign_parameter = sys_parameters.copy()
- sign_parameter.update(application_parameter)
-
- header = self.get_request_header();
- if(self.getMultipartParas()):
- form = MultiPartForm()
- for key, value in list(application_parameter.items()):
- form.add_field(key, value)
- for key in self.getMultipartParas():
- fileitem = getattr(self,key)
- if(fileitem and isinstance(fileitem,FileItem)):
- form.add_file(key,fileitem.filename,fileitem.content)
- body = str(form)
- header['Content-type'] = form.get_content_type()
- else:
- body = urllib.parse.urlencode(application_parameter)
-
- if(accessKey != ''):
- timestamp = str(int(round(time.time()))) + '000'
- print(("timestamp:" + timestamp))
- canonicalString = self.getCanonicalStringForIsv(timestamp, suiteTicket)
- print(("canonicalString:" + canonicalString))
- print(("accessSecret:" + accessSecret))
- signature = self.computeSignature(accessSecret, canonicalString)
- print(("signature:" + signature))
- ps = {}
- ps["accessKey"] = accessKey
- ps["signature"] = signature
- ps["timestamp"] = timestamp
- if(suiteTicket != ''):
- ps["suiteTicket"] = suiteTicket
- if(corpId != ''):
- ps["corpId"] = corpId
- queryStr = urllib.parse.urlencode(ps)
- if (self.__path.find("?") > 0):
- fullPath = self.__path + "&" + queryStr
- else:
- fullPath = self.__path + "?" + queryStr
- print(("fullPath:" + fullPath))
- else:
- if (self.__path.find("?") > 0):
- fullPath = (self.__path + "&access_token=" + str(authrize)) if len(str(authrize)) > 0 else self.__path
- else:
- fullPath = (self.__path + "?access_token=" + str(authrize)) if len(str(authrize)) > 0 else self.__path
- if(self.getHttpMethod() == "GET"):
- if (fullPath.find("?") > 0):
- fullPath = fullPath + "&" + body
- else:
- fullPath = fullPath + "?" + body
- connection.request(self.getHttpMethod(), fullPath, headers=header)
- else:
- if (self.getMultipartParas()):
- body = body
- else:
- body = json.dumps(application_parameter)
- connection.request(self.getHttpMethod(), fullPath, body=body, headers=header)
- response = connection.getresponse()
- if response.status != 200:
- raise RequestException('invalid http status ' + str(response.status) + ',detail body:' + response.read())
- result = response.read()
- # print("result:" + result)
- jsonobj = json.loads(result)
- if P_CODE in jsonobj and jsonobj[P_CODE] != 0:
- error = TopException()
- error.errcode = jsonobj[P_CODE]
- error.errmsg = jsonobj[P_MSG]
- error.application_host = response.getheader("Application-Host", "")
- error.service_host = response.getheader("Location-Host", "")
- raise error
- return jsonobj
-
- def getCanonicalStringForIsv(self, timestamp, suiteTicket):
- if(suiteTicket != ''):
- return timestamp + '\n' + suiteTicket
- else:
- return timestamp
- def computeSignature(self, secret, canonicalString):
- message = canonicalString.encode(encoding="utf-8")
- sec = secret.encode(encoding="utf-8")
- return str(base64.b64encode(hmac.new(sec, message, digestmod=hashlib.sha256).digest()))
-
- def getApplicationParameters(self):
- application_parameter = {}
- for key, value in self.__dict__.items():
- if not key.startswith("__") and not key in self.getMultipartParas() and not key.startswith("_RestApi__") and value is not None :
- if(key.startswith("_")):
- application_parameter[key[1:]] = value
- else:
- application_parameter[key] = value
- #查询翻译字典来规避一些关键字属性
- translate_parameter = self.getTranslateParas()
- for key, value in application_parameter.items():
- if key in translate_parameter:
- application_parameter[translate_parameter[key]] = application_parameter[key]
- del application_parameter[key]
- return application_parameter
|