base.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. # -*- coding: utf-8 -*-
  2. '''
  3. Created on 2012-7-3
  4. @author: lihao
  5. '''
  6. try: import httplib
  7. except ImportError:
  8. import http.client as httplib
  9. import urllib
  10. import time
  11. import hashlib
  12. import json
  13. import top
  14. import itertools
  15. import mimetypes
  16. '''
  17. 定义一些系统变量
  18. '''
  19. SYSTEM_GENERATE_VERSION = "taobao-sdk-python-20200219"
  20. P_APPKEY = "app_key"
  21. P_API = "method"
  22. P_SESSION = "session"
  23. P_ACCESS_TOKEN = "access_token"
  24. P_VERSION = "v"
  25. P_FORMAT = "format"
  26. P_TIMESTAMP = "timestamp"
  27. P_SIGN = "sign"
  28. P_SIGN_METHOD = "sign_method"
  29. P_PARTNER_ID = "partner_id"
  30. P_CODE = 'code'
  31. P_SUB_CODE = 'sub_code'
  32. P_MSG = 'msg'
  33. P_SUB_MSG = 'sub_msg'
  34. N_REST = '/router/rest'
  35. def sign(secret, parameters):
  36. #===========================================================================
  37. # '''签名方法
  38. # @param secret: 签名需要的密钥
  39. # @param parameters: 支持字典和string两种
  40. # '''
  41. #===========================================================================
  42. # 如果parameters 是字典类的话
  43. if hasattr(parameters, "items"):
  44. keys = parameters.keys()
  45. keys.sort()
  46. parameters = "%s%s%s" % (secret,
  47. str().join('%s%s' % (key, parameters[key]) for key in keys),
  48. secret)
  49. sign = hashlib.md5(parameters).hexdigest().upper()
  50. return sign
  51. def mixStr(pstr):
  52. if(isinstance(pstr, str)):
  53. return pstr
  54. elif(isinstance(pstr, unicode)):
  55. return pstr.encode('utf-8')
  56. else:
  57. return str(pstr)
  58. class FileItem(object):
  59. def __init__(self,filename=None,content=None):
  60. self.filename = filename
  61. self.content = content
  62. class MultiPartForm(object):
  63. """Accumulate the data to be used when posting a form."""
  64. def __init__(self):
  65. self.form_fields = []
  66. self.files = []
  67. self.boundary = "PYTHON_SDK_BOUNDARY"
  68. return
  69. def get_content_type(self):
  70. return 'multipart/form-data; boundary=%s' % self.boundary
  71. def add_field(self, name, value):
  72. """Add a simple field to the form data."""
  73. self.form_fields.append((name, str(value)))
  74. return
  75. def add_file(self, fieldname, filename, fileHandle, mimetype=None):
  76. """Add a file to be uploaded."""
  77. body = fileHandle.read()
  78. if mimetype is None:
  79. mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
  80. self.files.append((mixStr(fieldname), mixStr(filename), mixStr(mimetype), mixStr(body)))
  81. return
  82. def __str__(self):
  83. """Return a string representing the form data, including attached files."""
  84. # Build a list of lists, each containing "lines" of the
  85. # request. Each part is separated by a boundary string.
  86. # Once the list is built, return a string where each
  87. # line is separated by '\r\n'.
  88. parts = []
  89. part_boundary = '--' + self.boundary
  90. # Add the form fields
  91. parts.extend(
  92. [ part_boundary,
  93. 'Content-Disposition: form-data; name="%s"' % name,
  94. 'Content-Type: text/plain; charset=UTF-8',
  95. '',
  96. value,
  97. ]
  98. for name, value in self.form_fields
  99. )
  100. # Add the files to upload
  101. parts.extend(
  102. [ part_boundary,
  103. 'Content-Disposition: file; name="%s"; filename="%s"' % \
  104. (field_name, filename),
  105. 'Content-Type: %s' % content_type,
  106. 'Content-Transfer-Encoding: binary',
  107. '',
  108. body,
  109. ]
  110. for field_name, filename, content_type, body in self.files
  111. )
  112. # Flatten the list and add closing boundary marker,
  113. # then return CR+LF separated data
  114. flattened = list(itertools.chain(*parts))
  115. flattened.append('--' + self.boundary + '--')
  116. flattened.append('')
  117. return '\r\n'.join(flattened)
  118. class TopException(Exception):
  119. #===========================================================================
  120. # 业务异常类
  121. #===========================================================================
  122. def __init__(self):
  123. self.errorcode = None
  124. self.message = None
  125. self.subcode = None
  126. self.submsg = None
  127. self.application_host = None
  128. self.service_host = None
  129. def __str__(self, *args, **kwargs):
  130. sb = "errorcode=" + mixStr(self.errorcode) +\
  131. " message=" + mixStr(self.message) +\
  132. " subcode=" + mixStr(self.subcode) +\
  133. " submsg=" + mixStr(self.submsg) +\
  134. " application_host=" + mixStr(self.application_host) +\
  135. " service_host=" + mixStr(self.service_host)
  136. return sb
  137. class RequestException(Exception):
  138. #===========================================================================
  139. # 请求连接异常类
  140. #===========================================================================
  141. pass
  142. class RestApi(object):
  143. #===========================================================================
  144. # Rest api的基类
  145. #===========================================================================
  146. def __init__(self, domain='gw.api.taobao.com', port = 80):
  147. #=======================================================================
  148. # 初始化基类
  149. # Args @param domain: 请求的域名或者ip
  150. # @param port: 请求的端口
  151. #=======================================================================
  152. self.__domain = domain
  153. self.__port = port
  154. self.__httpmethod = "POST"
  155. if(top.getDefaultAppInfo()):
  156. self.__app_key = top.getDefaultAppInfo().appkey
  157. self.__secret = top.getDefaultAppInfo().secret
  158. def get_request_header(self):
  159. return {
  160. 'Content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
  161. "Cache-Control": "no-cache",
  162. "Connection": "Keep-Alive",
  163. }
  164. def set_app_info(self, appinfo):
  165. #=======================================================================
  166. # 设置请求的app信息
  167. # @param appinfo: import top
  168. # appinfo top.appinfo(appkey,secret)
  169. #=======================================================================
  170. self.__app_key = appinfo.appkey
  171. self.__secret = appinfo.secret
  172. def getapiname(self):
  173. return ""
  174. def getMultipartParas(self):
  175. return [];
  176. def getTranslateParas(self):
  177. return {};
  178. def _check_requst(self):
  179. pass
  180. def getResponse(self, authrize=None, timeout=30):
  181. #=======================================================================
  182. # 获取response结果
  183. #=======================================================================
  184. if(self.__port == 443):
  185. connection = httplib.HTTPSConnection(self.__domain, self.__port, None, None, False, timeout)
  186. else:
  187. connection = httplib.HTTPConnection(self.__domain, self.__port, False, timeout)
  188. sys_parameters = {
  189. P_FORMAT: 'json',
  190. P_APPKEY: self.__app_key,
  191. P_SIGN_METHOD: "md5",
  192. P_VERSION: '2.0',
  193. P_TIMESTAMP: str(long(time.time() * 1000)),
  194. P_PARTNER_ID: SYSTEM_GENERATE_VERSION,
  195. P_API: self.getapiname(),
  196. }
  197. if authrize is not None:
  198. sys_parameters[P_SESSION] = authrize
  199. application_parameter = self.getApplicationParameters()
  200. sign_parameter = sys_parameters.copy()
  201. sign_parameter.update(application_parameter)
  202. sys_parameters[P_SIGN] = sign(self.__secret, sign_parameter)
  203. connection.connect()
  204. header = self.get_request_header();
  205. if(self.getMultipartParas()):
  206. form = MultiPartForm()
  207. for key, value in application_parameter.items():
  208. form.add_field(key, value)
  209. for key in self.getMultipartParas():
  210. fileitem = getattr(self,key)
  211. if(fileitem and isinstance(fileitem,FileItem)):
  212. form.add_file(key,fileitem.filename,fileitem.content)
  213. body = str(form)
  214. header['Content-type'] = form.get_content_type()
  215. else:
  216. body = urllib.urlencode(application_parameter)
  217. url = N_REST + "?" + urllib.urlencode(sys_parameters)
  218. connection.request(self.__httpmethod, url, body=body, headers=header)
  219. response = connection.getresponse();
  220. if response.status is not 200:
  221. raise RequestException('invalid http status ' + str(response.status) + ',detail body:' + response.read())
  222. result = response.read()
  223. jsonobj = json.loads(result)
  224. if jsonobj.has_key("error_response"):
  225. error = TopException()
  226. if jsonobj["error_response"].has_key(P_CODE) :
  227. error.errorcode = jsonobj["error_response"][P_CODE]
  228. if jsonobj["error_response"].has_key(P_MSG) :
  229. error.message = jsonobj["error_response"][P_MSG]
  230. if jsonobj["error_response"].has_key(P_SUB_CODE) :
  231. error.subcode = jsonobj["error_response"][P_SUB_CODE]
  232. if jsonobj["error_response"].has_key(P_SUB_MSG) :
  233. error.submsg = jsonobj["error_response"][P_SUB_MSG]
  234. error.application_host = response.getheader("Application-Host", "")
  235. error.service_host = response.getheader("Location-Host", "")
  236. raise error
  237. return jsonobj
  238. def getApplicationParameters(self):
  239. application_parameter = {}
  240. for key, value in self.__dict__.iteritems():
  241. if not key.startswith("__") and not key in self.getMultipartParas() and not key.startswith("_RestApi__") and value is not None :
  242. if(key.startswith("_")):
  243. application_parameter[key[1:]] = value
  244. else:
  245. application_parameter[key] = value
  246. #查询翻译字典来规避一些关键字属性
  247. translate_parameter = self.getTranslateParas()
  248. for key, value in application_parameter.iteritems():
  249. if key in translate_parameter:
  250. application_parameter[translate_parameter[key]] = application_parameter[key]
  251. del application_parameter[key]
  252. return application_parameter