node-easywechat
Version:
EasyWechat SDK for Node.js (NOT OFFICIAL)
188 lines (187 loc) • 7.55 kB
JavaScript
'use strict';
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const fs_1 = __importDefault(require("fs"));
const merge_1 = __importDefault(require("merge"));
const Utils_1 = require("../Core/Support/Utils");
const HttpClient_1 = __importDefault(require("../Core/HttpClient/HttpClient"));
const HttpClientMethodsMixin_1 = __importDefault(require("../Core/HttpClient/Mixins/HttpClientMethodsMixin"));
const PresetMixin_1 = __importDefault(require("../Core/HttpClient/Mixins/PresetMixin"));
const Signature_1 = __importDefault(require("./Signature"));
const LegacySignature_1 = __importDefault(require("./LegacySignature"));
const form_data_1 = __importDefault(require("form-data"));
class Client {
constructor(merchant, client, defaultOptions = {}) {
var _a;
this.merchant = merchant;
this.throw = true;
this.client = null;
this.defaultOptions = {
baseURL: 'https://api.mch.weixin.qq.com',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
};
this.V3_URI_PREFIXES = [
'/v3/',
'/sandbox/v3/',
'/hk/v3/',
'/global/v3/',
];
this.throw = !!((_a = defaultOptions['throw']) !== null && _a !== void 0 ? _a : true);
this.defaultOptions = merge_1.default.recursive(true, this.defaultOptions, defaultOptions);
this.client = client || HttpClient_1.default.create();
}
getInstance() {
return this.client.getInstance();
}
setInstance(instance) {
this.client.setInstance(instance);
return this;
}
setLogger(logger) {
this.client.setLogger(logger);
return this;
}
request(method, url, payload = {}) {
return __awaiter(this, void 0, void 0, function* () {
if (!payload.headers)
payload.headers = {};
if (!payload.headers['user-agent'] && !payload.headers['User-Agent']) {
payload.headers['user-agent'] = (0, Utils_1.createUserAgent)();
}
if (this.isV3Request(url)) {
payload.headers['authorization'] = this.createSignature(method, url, payload);
}
else {
if (payload.xml) {
if (Array.isArray(payload.xml)) {
payload.xml = (0, Utils_1.buildXml)(this.attachLegacySignature(payload.xml));
}
if (typeof payload.xml !== 'string') {
throw new Error('The `xml` option must be a string or object.');
}
payload.data = payload.xml;
delete payload.xml;
}
if (payload.data && typeof payload.data === 'object') {
payload.data = (0, Utils_1.buildXml)(this.attachLegacySignature(payload.data));
}
if (!payload.headers['content-type'] && !payload.headers['Content-Type']) {
payload.headers['content-type'] = 'text/xml';
}
}
if (this.prependData && Object.keys(this.prependData).length > 0) {
payload.data = Object.assign(Object.assign({}, this.prependData), payload.data);
}
if (this.prependHeaders && Object.keys(this.prependHeaders).length > 0) {
payload.headers = Object.assign(Object.assign({}, this.prependHeaders), payload.headers);
}
return this.client.request(method, (0, Utils_1.ltrim)(url, '\\/+'), payload);
});
}
/**
* 文件上传
* @see https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter2_1_1.shtml
* @param uri 接口地址
* @param file 文件路径或文件可读流
* @param meta 文件元信息,包含 filename 和 sha256 两个字段
* @param filename 文件名,必须以 .jpg、.bmp、.png 为后缀
* @returns
*/
uploadMedia(uri, file, meta = null, filename = null) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof file === 'string') {
file = fs_1.default.createReadStream(file);
}
if (!meta) {
meta = {
filename: filename !== null && filename !== void 0 ? filename : 'file.jpg',
sha256: yield (0, Utils_1.createFileHash)(file, 'sha256'),
};
}
let metaJson = JSON.stringify(meta);
let formData = new form_data_1.default();
formData.append('file', file);
formData.append('meta', metaJson, {
contentType: 'application/json',
});
return this.client.request('POST', (0, Utils_1.ltrim)(uri, '\\/+'), {
formData,
headers: {
'authorization': this.createSignature('POST', uri, {
data: metaJson,
}),
}
});
});
}
/**
* 判断是否是V3请求
* @param url 请求地址
* @returns
*/
isV3Request(url) {
let pathname = url;
if (url.startsWith('https://') || url.startsWith('http://')) {
let urlObj = new URL(url);
pathname = urlObj.pathname;
}
for (let i = 0; i < this.V3_URI_PREFIXES.length; i++) {
if (pathname.startsWith(this.V3_URI_PREFIXES[i])) {
return true;
}
}
return false;
}
/**
* 创建签名(V3)
* @param method 请求方式
* @param url 请求地址
* @param payload 请求载荷
* @returns
*/
createSignature(method, url, payload) {
return (new Signature_1.default(this.merchant)).createHeader(method, url, payload);
}
/**
* 创建签名(V2)
* @param body 请求参数
* @returns
*/
attachLegacySignature(body) {
return (new LegacySignature_1.default(this.merchant)).sign(body);
}
/**
* 预设置mch_id(因nodejs不支持魔术方法,只好预先设置几个常用的方法)
* @param new_mch_id
* @returns
*/
withMchId(new_mch_id = null) {
this.with('mch_id', new_mch_id);
return this;
}
/**
* 预设置mch_id别名(因nodejs不支持魔术方法,只好预先设置几个常用的方法)
* @param new_alias
* @returns
*/
withMchIdAs(new_alias = null) {
this.with(new_alias, this.presets['mch_id']);
return this;
}
}
;
(0, Utils_1.applyMixins)(Client, [HttpClientMethodsMixin_1.default, PresetMixin_1.default]);
module.exports = Client;