UNPKG

sync-alisdk

Version:

Taobao Open API & Message Client.

365 lines (339 loc) 10.1 kB
var util = require("../topUtil.js"); var RestClient = require("./network.js"); var Stream = require("stream"); const v8 = require("v8"); /** * TOP API Client. * * @param {Object} options, must set `appkey` and `appsecret`. * @constructor */ class TopClient { constructor(options) { options = options || {}; if (!options.appkey || !options.appsecret) { throw new Error("appkey or appsecret need!"); } this.url = options.url || "http://gw.api.taobao.com/router/rest"; this.platform = options.platform || "aliexpress"; this.appkey = options.appkey; this.appsecret = options.appsecret; this.newApi = options.newApi; } /** * Invoke an api by method name. * * @param {String} method, method name * @param {Object} params * @param {Array} reponseNames, e.g. ['tmall_selected_items_search_response', 'tem_list', 'selected_item'] * @param {Object} defaultResponse * @param {Function(err, response)} callback */ invoke(type, method, params, bigIntParamName, reponseNames, callback) { params.method = method; const cb = (err, result) => { if (err) { return callback(err); } var response = result; if (reponseNames && reponseNames.length > 0) { var retResult = undefined; for (var i = 0; i < reponseNames.length; i++) { var name = reponseNames[i]; retResult = response[name]; if (retResult != undefined) { response = retResult; break; } } } callback(null, response); }; if (this.platform === "aliexpress") { return this.request(type, params, bigIntParamName, cb); } if (this.platform === "lazada") { return this.lazadaRequest(type, params, cb); } } /** * Request API. * * @param {Object} params * @param {String} [type='GET'] * @param {Function(err, result)} callback * @param {number} retry * @public */ request(type, params, bigIntParamName, callback, retry = 10) { const backupParams = v8.deserialize(v8.serialize(params)); const skipAuth = params.skipAuth; if (skipAuth) { delete params.skipAuth; } else { let err = util.checkRequired(params, ["sessionInfo", "method"]); // const now = Date.now(); // const thirdExpiredTime = params.sessionInfo.sessionExpireTime + 86400000; // if (now > thirdExpiredTime) { // err = new Error('店铺授权已过期, 请到速卖通服务市场免费订购后,回到控制台重新添加授权'); // err.code = 27; // } if (err) { return callback(err); } if (this.newApi) { params.access_token = params.sessionInfo.session; }else { params.session = params.sessionInfo.session; } delete params.sessionInfo; } const args = { timestamp: Date.now(), format: "json", app_key: this.appkey, v: "2.0", sign_method: this.newApi ? "sha256" : "md5", }; let request = null; if (type === "get") { request = RestClient.get(this.url, { "Accept-Encoding": "gzip, deflate", }); } else { request = RestClient.post(this.url, { "Accept-Encoding": "gzip, deflate", }); } for (var key in params) { if (typeof params[key] === "object" && Buffer.isBuffer(params[key])) { request.attach(key, params[key], { knownLength: params[key].length, filename: key, }); } else if (typeof params[key] === "object") { args[key] = JSON.stringify(params[key]); } else { args[key] = params[key]; } } args.sign = this.newApi ? this.hmac_sign(args, params.method, this.url === 'https://api-sg.aliexpress.com/rest') : this.sign(args); for (var key in args) { request.field(key, args[key]); } const that = this; request.end(function (response) { if (response.statusCode === 200) { const data = response.body; const errRes = data && data.error_response; if (errRes && !errRes.message) { //不加这句async.js不会处理error errRes.message = errRes.msg || "xxx"; } if (errRes) { if ( (errRes.code === 15 || errRes.code === "15" || errRes.code === "UnknownRuntimeException" || errRes.code === "IncompleteSignature" || errRes.code === "ServiceTimeout") && retry > 0 ) { // console.log(`retry retry ${retry}`, backupParams); that.request( type, backupParams, bigIntParamName, callback, retry - 1 ); return; } // if (errRes.code === 'ApiCallLimit' && retry > 0) { // setTimeout(() => { // that.request(type, backupParams, bigIntParamName, callback, retry - 1); // }, 1000); // return; // } if (errRes.code === "IllegalAccessToken") { errRes.message = "店铺授权已过期, 请到速卖通服务市场订购后,回到控制台重新添加授权"; } console.log("errRes", errRes, params, args); callback(errRes, data); } else { callback(null, data); } } else { if (retry > 0) { that.request( type, backupParams, bigIntParamName, callback, retry - 1 ); return; } console.log("response", response.statusCode, response.body); const err = new Error("NetWork-Error"); err.name = "NetWork-Error"; err.code = 15; err.sub_code = response.statusCode; callback(err, null); } }, bigIntParamName); } // when request access_token set params.isAuthRequest = true lazadaRequest(type, params, callback) { const isAuthRequest = params.isAuthRequest; let err = util.checkRequired(params, ["method"]); if (!isAuthRequest) { err = util.checkRequired(params, ["sessionInfo"]); } if (err) { return callback(err); } const now = Date.now(); if (!isAuthRequest) { const thirdExpiredTime = params.sessionInfo.sessionExpireTime - 5000; if (now > thirdExpiredTime) { err = new Error( "店铺授权已过期, 请到速卖通服务市场免费订购后,回到控制台重新添加授权" ); err.code = 27; return callback(err); } params.access_token = params.sessionInfo.session; delete params.sessionInfo; } else { delete params.isAuthRequest; } const method = params.method; delete params.method; let args = { timestamp: now, app_key: this.appkey, sign_method: "sha256", }; var request = null; const url = this.url + method; if (type == "get") { request = RestClient.get(url); } else { request = RestClient.post(url); } for (var key in params) { if (typeof params[key] === "object" && Buffer.isBuffer(params[key])) { request.attach(key, params[key], { knownLength: params[key].length, filename: key, }); } else if (typeof params[key] === "object") { args[key] = JSON.stringify(params[key]); } else { args[key] = params[key]; } } args.sign = this.hmac_sign(args, method); for (var key in args) { request.field(key, args[key]); } request.end(function (response) { if (response.statusCode == 200) { var data = response.body; var errRes = data && data.error_response; if (errRes && !errRes.message) { //不加这句async.js不会处理error errRes.message = errRes.msg || "xxx"; } if (errRes) { callback(errRes, data); } else { callback(err, data); } } else { err = new Error("NetWork-Error"); err.name = "NetWork-Error"; err.code = 15; err.sub_code = response.statusCode; callback(err, null); } }); } /** * Get now timestamp with 'yyyy-MM-dd HH:mm:ss' format. * @return {String} */ timestamp() { return util.YYYYMMDDHHmmss(); } /** * Sign API request. * see http://open.taobao.com/doc/detail.htm?id=111#s6 * * @param {Object} params * @return {String} sign string */ sign(params) { var sorted = Object.keys(params).sort(); let basestring = this.appsecret; for (let i = 0, l = sorted.length; i < l; i++) { var k = sorted[i]; basestring += k + params[k]; } basestring += this.appsecret; return util.md5(basestring).toUpperCase(); } hmac_sign(params, api_name, need_api_head=false) { var sorted = Object.keys(params).sort(); let basestring = need_api_head ? api_name : ""; for (var i = 0, l = sorted.length; i < l; i++) { var k = sorted[i]; basestring += k + params[k]; } return util.hmac_sha256(basestring, this.appsecret).toUpperCase(); } doExecute(apiname, params, bigIntParamName) { let that = this; return new Promise(function (resolve, reject) { that.invoke( "post", apiname, params, bigIntParamName, [util.getApiResponseName(apiname)], (err, response) => { if (err) { return reject(err); } resolve(response); } ); }); } /** * execute top api */ execute(apiname, params, bigIntParamName) { let that = this; return new Promise(function (resolve, reject) { that.invoke( "post", apiname, params, bigIntParamName, [util.getApiResponseName(apiname)], (err, response) => { if (err) { return reject(err); } resolve(response); } ); }); } } exports.TopClient = TopClient;