公众号 生成二维码接口

This commit is contained in:
Wang Kejun 2022-11-15 17:16:41 +08:00
parent f5bf7329d2
commit 4a26e1df1e
3 changed files with 149 additions and 15 deletions

View File

@ -12,4 +12,14 @@ export declare class WechatPublicInstance {
}>;
private refreshAccessToken;
decryptData(sessionKey: string, encryptedData: string, iv: string, signature: string): any;
getQrCode(options: {
sceneId?: number;
sceneStr?: string;
expireSeconds?: number;
isPermanent?: boolean;
}): Promise<{
ticket: any;
url: any;
expireSeconds: any;
}>;
}

View File

@ -36,9 +36,9 @@ var WechatPublicInstance = /** @class */ (function () {
}
return [2 /*return*/, json];
case 3:
if (!(contentType.includes('text')
|| contentType.includes('xml')
|| contentType.includes('html'))) return [3 /*break*/, 5];
if (!(contentType.includes('text') ||
contentType.includes('xml') ||
contentType.includes('html'))) return [3 /*break*/, 5];
return [4 /*yield*/, response.text()];
case 4:
data = _a.sent();
@ -105,6 +105,64 @@ var WechatPublicInstance = /** @class */ (function () {
}
return data;
};
WechatPublicInstance.prototype.getQrCode = function (options) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var sceneId, sceneStr, expireSeconds, isPermanent, scene, actionName, myInit, result;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
sceneId = options.sceneId, sceneStr = options.sceneStr, expireSeconds = options.expireSeconds, isPermanent = options.isPermanent;
if (!sceneId && !sceneStr) {
throw new Error('Missing sceneId or sceneStr');
}
scene = sceneId
? {
scene_id: sceneId,
}
: {
scene_str: sceneStr,
};
actionName = sceneId ? 'QR_SCENE' : 'QR_STR_SCENE';
myInit = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
expire_seconds: expireSeconds,
action_name: actionName,
action_info: {
scene: scene,
},
}),
};
if (isPermanent) {
actionName = sceneId ? 'QR_LIMIT_SCENE' : 'QR_LIMIT_STR_SCENE';
myInit = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action_name: actionName,
action_info: {
scene: scene,
},
}),
};
}
return [4 /*yield*/, this.access("https://api.weixin.qq.com/cgi-bin/qrcode/create??access_token=".concat(this.accessToken), myInit)];
case 1:
result = _a.sent();
return [2 /*return*/, {
ticket: result.ticket,
url: result.url,
expireSeconds: result.expire_seconds,
}];
}
});
});
};
return WechatPublicInstance;
}());
exports.WechatPublicInstance = WechatPublicInstance;

View File

@ -20,23 +20,26 @@ export class WechatPublicInstance {
return mockData;
}
const response = await global.fetch(url, init);
const { headers, status } = response;
if (![200, 201].includes(status)) {
throw new Error(`微信服务器返回不正确应答:${status}`);
}
const contentType = (headers as any)['Content-Type'] || headers.get('Content-Type')!;
const contentType =
(headers as any)['Content-Type'] || headers.get('Content-Type')!;
if (contentType.includes('application/json')) {
const json = await response.json();
if (typeof json.errcode === 'number' && json.errcode !== 0) {
throw new Error(`调用微信接口返回出错code是${json.errcode},信息是${json.errmsg}`);
throw new Error(
`调用微信接口返回出错code是${json.errcode},信息是${json.errmsg}`
);
}
return json;
}
if (
contentType.includes('text')
|| contentType.includes('xml')
|| contentType.includes('html')
contentType.includes('text') ||
contentType.includes('xml') ||
contentType.includes('html')
) {
const data = await response.text();
return data;
@ -48,12 +51,13 @@ export class WechatPublicInstance {
return response;
}
async code2Session(code: string) {
async code2Session(code: string) {
const result = await this.access(
`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${this.appId}&secret=${this.appSecret}&code=${code}&grant_type=authorization_code`,
{ session_key: 'aaa', openid: code, unionid: code }
);
const { session_key, openid, unionid } = typeof result === 'string' ? JSON.parse(result) : result; // 这里微信返回的数据有时候竟然是text/plain
const { session_key, openid, unionid } =
typeof result === 'string' ? JSON.parse(result) : result; // 这里微信返回的数据有时候竟然是text/plain
return {
sessionKey: session_key as string,
@ -75,19 +79,22 @@ export class WechatPublicInstance {
}, (expires_in - 10) * 1000);
}
decryptData(sessionKey: string, encryptedData: string, iv: string, signature: string) {
decryptData(
sessionKey: string,
encryptedData: string,
iv: string,
signature: string
) {
const skBuf = Buffer.from(sessionKey, 'base64');
// const edBuf = Buffer.from(encryptedData, 'base64');
const ivBuf = Buffer.from(iv, 'base64');
const decipher = crypto.createDecipheriv('aes-128-cbc', skBuf, ivBuf);
// 设置自动 padding 为 true删除填充补位
decipher.setAutoPadding(true);
let decoded = decipher.update(encryptedData, 'base64', 'utf8');
decoded += decipher.final('utf8');
const data = JSON.parse(decoded);
if (data.watermark.appid !== this.appId) {
@ -96,4 +103,63 @@ export class WechatPublicInstance {
return data;
}
async getQrCode(options: {
sceneId?: number;
sceneStr?: string;
expireSeconds?: number;
isPermanent?: boolean;
}) {
const { sceneId, sceneStr, expireSeconds, isPermanent } = options;
if (!sceneId && !sceneStr) {
throw new Error('Missing sceneId or sceneStr');
}
const scene = sceneId
? {
scene_id: sceneId,
}
: {
scene_str: sceneStr,
};
let actionName = sceneId ? 'QR_SCENE' : 'QR_STR_SCENE';
let myInit = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
expire_seconds: expireSeconds,
action_name: actionName,
action_info: {
scene,
},
}),
};
if (isPermanent) {
actionName = sceneId ? 'QR_LIMIT_SCENE' : 'QR_LIMIT_STR_SCENE';
myInit = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action_name: actionName,
action_info: {
scene,
},
}),
};
}
const result = await this.access(
`https://api.weixin.qq.com/cgi-bin/qrcode/create??access_token=${this.accessToken}`,
myInit
);
return {
ticket: result.ticket,
url: result.url,
expireSeconds: result.expire_seconds,
};
}
};