const needle = require('needle'); const moment = require('moment'); const {Class} = require('./Class'); const {RequestType} = require('./RequestType'); const {SignUtil} = require('./SignUtil'); const {BaseRequest} = require('../request/BaseRequest'); const HEADERS = {'Accept-Encoding': 'identity'}; const getHeaders = function (headers) { if (!headers) { return HEADERS; } for (const key in HEADERS) { headers[key] = HEADERS[key]; } return headers; }; const OpenClient = Class.create({ /** * 初始化客户端 * @param appId 应用ID * @param privateKey 应用私钥,2048位,PKCS8 * @param url 请求url */ init: function (appId, privateKey, url) { this.appId = appId; this.privateKey = privateKey; this.url = url; }, /** * 发送请求 * @param request 请求类 * @param callback 回调函数,参数json(undefined则使用executeSync) */ execute: function (request, callback) { if (typeof callback == 'function') { this.executeToken(request, null, callback); } else { return this.executeSync(request); } }, /** * 发送同步请求 * @param request 请求类 * */ executeSync: function (request) { return new Promise((resolve) => { this.execute(request, res => { resolve(res); }); }); }, /** * 发送请求 * @param request 请求类 * @param token token * @param callback 回调函数,参数json(undefined则使用executeTokenSync) */ executeToken: function (request, token, callback) { if (!(request instanceof BaseRequest)) { throw 'request类未继承BaseRequest'; } if (typeof callback == 'function') { const requestType = request.getRequestType(); if (request.files) { this._postFile(request, callback); } else { switch (requestType) { case RequestType.GET: this._get(request, callback); break; case RequestType.POST_FORM: this._postForm(request, callback); break; case RequestType.POST_JSON: this._postJson(request, callback); break; case RequestType.POST_FILE: this._postFile(request, callback); break; default: { throw 'request.getRequestType()类型不正确'; } } } } else { return this.executeTokenSync(request, token); } }, /** * 发送同步请求 * @param request 请求类 * @param token token */ executeTokenSync: function (request, token) { return new Promise((resolve) => { this.executeToken(request, token, res => { resolve(res); }); }); }, _get: function (request, callback) { const allParams = this._buildParams(request); const that = this; // needle.request(method, url, data[, options][, callback]) needle.request('GET', this.url, allParams, { headers: getHeaders() }, function (error, response) { callback(that._parseResponse(error, response, request)); }); }, _postForm: function (request, callback) { const allParams = this._buildParams(request); const that = this; needle.request('POST', this.url, allParams, { headers: getHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }) }, function (error, response) { callback(that._parseResponse(error, response, request)); }); }, _postJson: function (request, callback) { const allParams = this._buildParams(request); const that = this; needle.request('POST', this.url, allParams, { headers: getHeaders(), json: true }, function (error, response) { callback(that._parseResponse(error, response, request)); }); }, _postFile: function (request, callback) { const allParams = this._buildParams(request); const files = request.files; files.forEach(row => { // 设置成{ file: row.path, content_type: 'application/octet-stream' }格式 // needle会认为是上传文件 allParams[row.name] = {file: row.path, content_type: 'application/octet-stream'}; }); const that = this; needle.request('POST', this.url, allParams, { headers: getHeaders(), multipart: true }, function (error, response) { callback(that._parseResponse(error, response, request)); }); }, _parseResponse: function (error, response, request) { if (!error && response.statusCode === 200) { return request.parseResponse(response.body); } else { // throw '请求异常:' + error return { // 重新封装请求异常回调,以防中断 msg: '请求异常', code: '502', sub_msg: `${error}`, sub_code: 'isv.invalid-server' }; } }, _buildParams: function (request, token) { const allParams = { 'app_id': this.appId, 'method': request.getMethod(), 'charset': 'UTF-8', 'sign_type': 'RSA2', 'timestamp': moment().format('YYYY-MM-DD HH:mm:ss'), 'version': request.getVersion(), 'biz_content': JSON.stringify(request.bizModel) }; if (token) { allParams['app_auth_token'] = token; } // 创建签名 const sign = SignUtil.createSign(allParams, this.privateKey, 'RSA2'); allParams.sign = sign; return allParams; } }); module.exports = OpenClient;