微信公众号、微信程序开、微信小游戏、微信支付以及企业微信等服务端API nestjs 模块封装。也可以直接当工具类使用。
nest-wechat是自用业务的封装,如果你需要用到的api还没有,可以提 issues 给我,我会尽快补上。
npm i --save nest-wechat- register方法注册
import { Module } from '@nestjs/common';
import { WeChatModule } from 'nest-wechat';
@Module({
imports: [WeChatModule.register({appId: 'your app id', secret: 'your secret'})],
})
export class AppModule {
}- forRoot配置注册
import { CACHE_MANAGER, Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { Cache } from 'cache-manager';
import { RedisCache, WeChatModule } from 'nest-wechat';
@Module({
imports: [
ConfigModule.forRoot({
envFilePath: '.env.test.local',
}),
WeChatModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService, CACHE_MANAGER],
useFactory: (configService: ConfigService, cache: Cache) => ({
appId: configService.get('WX_APPID'),
secret: configService.get('WX_SECRET'),
token: configService.get('WX_TOKEN'),
encodingAESKey: configService.get('WX_AESKEY'),
cacheAdapter: new RedisCache(cache),
debug: true,
}),
}),
]
})
export class AppModule {
}import { WeChatService } from 'nest-wechat';
const service = new WeChatService({ appId: 'your app id', secret: 'your secret'});/**
* 缓存接口,需要自定义缓存,请实现该接口
*
* cache interface, please implement this interface if you need.
*
*/
export interface ICache {
get<T> (key: string): Promise<T>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
set (key: string, value: any): void;
remove (key: string): boolean;
close (): void;
}配置读写属性,类型:WeChatModuleOptions
缓存适配器读写属性,类型:ICache,默认是一个Map实现的缓存
public async getAccessTokenByCode (code: string, _appId?: string, _secret?: string): Promise<UserAccessTokenResult>;正确返回
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}错误返回
{
"errcode": 40029,
"errmsg": "invalid code"
}公众号拉取用户信息
public async getUserInfo (accessToken: string, openid: string, lang: 'zh_CN' | 'zh_TW' | 'en' = 'zh_CN'): Promise<UserInfoResult>;正确返回
{
"openid": "OPENID",
"nickname": NICKNAME,
"sex": 1,
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl":"https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}错误返回
{
"errcode":40003,
"errmsg":" invalid openid "
}public async getAccountAccessToken (_appId?: string, _secret?: string): Promise<AccountAccessTokenResult>;正确返回
{
"access_token": "52_s0Mcl3E3DBKs12rthjxG8_DOvsIC4puV9A34WQR6Bhb_30TW9W9BjhUxDRkyph-hY9Ab2QS03Q8wZBe5UkA1k0q0hc17eUDZ7vAWItl4iahnhq_57dCoKc1dQ3AfiHUKGCCMJ2NcQ0BmbBRIKBEgAAAPGJ",
"expires_in": 7200
}错误返回
{
"errcode": 40013,
"errmsg": "invalid appid"
}public async getStableAccessToken (_appId?: string, _secret?: string, force = false): Promise<AccountAccessTokenResult>;public async getJSApiTicket (_appId?: string, _secret?: string): Promise<TicketResult>;返回数据
{
"errcode": 0,
"errmsg": "ok",
"ticket": "bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in": 7200
}public async jssdkSignature (url: string): Promise<SignatureResult>;
public async jssdkSignature (url: string, appId: string, secret:string): Promise<SignatureResult>;public async sendTemplateMessage (message: TemplateMessage, appId?: string, secret?: string): Promise<DefaultRequestResult & { msgid: string }>;public async createQRCode (data: AccountCreateQRCode, appId?: string, secret?: string): Promise<AccountCreateQRCodeResult>;public showQRCode (ticket: string): Promis<Buffer>;WeChatService.checkSignatureExpress (req: Request, res: Response);Usage:
@Get('push')
async pushTest (@Req() req: Request, @Res() res: Response) {
this.service.checkSignatureExpress(req, res);
}WeChatService.messagePushExpressHandler (req: Request, res?: Response, resText?: string);Usage:
@Post('push')
async officialPushTest (@Req() req: Request, @Res() res: Response) {
const decrypt = await this.service.messagePushExpressHandler(req, res);
}public getAccessToken (appId?: string, secret?: string): Promise<AccessTokenResult>;const service = new WeChatService({ appId: 'your app id', secret: 'your secret'});
const res = await service.mp.getAccessToken();
console.log(res.data.access_token);public async getRid (rid: string, accessToken: string): Promise<RidInfo>;public async getPluginOpenPId (code: string, accessToken: string): Promise<DefaultRequestResult & { openpid: string }>;public async code2Session (code: string, appId?: string, secret?: string): Promise<SessionResult>;返回数据
{
"openid": "openid",
"session_key": "key",
"unionid": "unionid",
"errcode": 0,
"errmsg": "ok",
}public async getPhoneNumber (code: string, accessToken: string);public async getQRCode (params: QRCode, accessToken: string): Promise<DefaultRequestResult & { contentType: string, buffer: Buffer }>;public getUnlimitedQRCode (params: GetUnlimitedQRCode, accessToken: string): Promise<DefaultRequestResult & { buffer: Buffer }>;public async createQRCode (params: CreateQRCode, accessToken: string): Promise<DefaultRequestResult & { contentType: string, buffer: Buffer }>;public async queryScheme (scheme: string, accessToken: string): Promise<DefaultRequestResult & { scheme_info: SchemeInfo, scheme_quota: SchemeQuota }>;public generateScheme (params: GenerateScheme, accessToken: string): Promise<DefaultRequestResult & { openlink: string >;public generateNFCScheme (params: GenerateNFCScheme, accessToken: string): Promise<DefaultRequestResult & { openlink: string }>;public generateUrlLink (params: GenerateUrlLink, accessToken: string): Promise<DefaultRequestResult & { url_link: string }>;public queryUrlLink (urlLink: string, accessToken: string): Promise<UrlLinkResult>;public generateShortLink (params: GenerateShortLink, accessToken: string): Promise<DefaultRequestResult & { link: string }>;public sendUniformMessage (params: SendUniformMessage, accessToken: string): Promise<DefaultRequestResult>;public createActivityId (params: CreateActivityId, accessToken: string): Promise<ActivityIdResult>;public setUpdatableMsg (params: UpdatableMsg, accessToken: string): Promise<DefaultRequestResult>;public deleteMessageTemplate (priTmplId: string, accessToken: string): Promise<DefaultRequestResult>;public getCategory (accessToken: string): Promise<DefaultRequestResult & { data: {id: number, name: string}[] }>;public getPubTemplateKeyWordsById (tid: number, accessToken: string): Promise<PubTemplateKeyWords>;public getPubTemplateTitleList (params: PubTemplateTitleList, accessToken: string): Promise<PubTemplateTitleListResult>;public getMessageTemplateList (accessToken: string): Promise<MessageTemplateListResult>;public sendMessage (params: SendMessage, accessToken: string): Promise<DefaultRequestResult>;public addMessageTemplate (params: MessageTemplate, accessToken: string): Promise<DefaultRequestResult & { priTmplId: string }>;Module导入
import { Module } from '@nestjs/common';
import { WeChatMobileModule } from 'nest-wechat';
@Module({
imports: [WeChatMobileModule.register()],
})
export class AppModule {
}工具类引入
import { MobileService } from 'nest-wechat';
const service = new MobileService();public getAccessToken (code: string, appId: string, secret: string): Promise<AxiosResponse<MobileAppAccessTokenResult, any>>;public refreshAccessToken (appId: string, refreshToken: string): Promise<AxiosResponse<MobileAppAccessTokenResult, any>>;public checkAccessToken (openId: string, accessToken: string): Promise<AxiosResponse<DefaultRequestResult, any>>;pay.jsapi (order: TransactionOrder, serialNo: string, privateKey: Buffer | string): Promise<{prepay_id: string}>;pay.getTransactionById (id: string, mchId: string, serialNo: string, privateKey: Buffer | string): Promise<Trade>;pay.getTransactionByOutTradeNo (outTradeNo: string, mchId: string, serialNo: string, privateKey: Buffer | string): Promise<Trade>;pay.close (outTradeNo: string, mchId: string, serialNo: string, privateKey: Buffer | string);pay.refund (refund: RequireOnlyOne<RefundParameters, 'transaction_id' | 'out_trade_no'>, mchId: string, serialNo: string, privateKey: Buffer | string): Promise<RefundResult>;pay.getRefund (outRefundNo: string, mchId: string, serialNo: string, privateKey: Buffer | string): Promise<RefundResult>;pay.buildMiniProgramPayment (appId: string, prepayId: string, privateKey: Buffer | string): MiniProgramPaymentParameters;pay.paidCallback (publicKey: Buffer | string, apiKey: string, req: Request, res: Response): Promise<Trade>;pay.refundedCallback (certs: Map<string, string>, apiKey: string, req: Request, res: Response): Promise<RefundNotifyResult>;pay.fapiaoDevConfig (data: DevelopmentConfigRequest, mchId: string, serialNo: string, privateKey: Buffer | string);pay.getFapiaoDevConfig (mchId: string, serialNo: string, privateKey: Buffer | string);pay.createCardTemplate (data: CreateCardTemplateRequest, mchId: string, serialNo: string, privateKey: Buffer | string);pay.fapiaoCallback (certs: Map<string, string>, apiKey: string, req: Request, res: Response): Promise<FapiaoNotifyResult>;pay.getUserTitle (params: GetUserTitleParams, mchId: string, serialNo: string, privateKey: Buffer | string);pay.issueFapiao (data: IssueFapiaoRequest, mchId: string, serialNo: string, privateKey: Buffer | string);pay.getIssueFapiao (fapiaoApplyId: string, fapiaoId: string, mchId: string, serialNo: string, privateKey: Buffer | string);pay.reverseFapiao (fapiaoApplyId: string, data: ReverseFapiaoRequest, mchId: string, serialNo: string, privateKey: Buffer | string);pay.rsaEncryptOAEP (text: string, publicKey: Buffer | string);pay.rsaDecryptOAEP (cipherText: string, privateKey: Buffer | string);没有可用测试商户,未做成功测试,请自行测试,有问题请提issue。
测试可自行执行单元测试(需要修改配置)
npm run test lib/wepay.hb.spec.tspay.sendRedPack(redPack: RedPackData, appId: string, mchId: string, apiKey: string, publicKey: Buffer | string, privateKey: Buffer | string, group = false): Promise<AxiosResponse<string, any>>;pay.sendGroupRedPack(redPack: GroupRedPackData, appId: string, mchId: string, apiKey: string, publicKey: Buffer | string, privateKey: Buffer | string): Promise<AxiosResponse<string, any>>;pay.getHbInfo(billNO: string, appId: string, mchId: string, apiKey: string, publicKey: Buffer | string, privateKey: Buffer | string): Promise<AxiosResponse<string, any>>;jsapiOfPartner (order: TransactionOrderOfPartner, serialNo: string, privateKey: Buffer | string);构建调起微信支付参数接口
buildJSAPIParameters (appId: string, prepayId: string, privateKey: Buffer | string): MiniProgramPaymentParameters;paidCallbackOfPartner (certs: Map<string, string>, apiKey: string, req: Request, res: Response): Promise<TradeOfPartner>;closeOfPartner (outTradeNo: string, spMchId: string, subMchId: string, serialNo: string, privateKey: Buffer | string);getTransactionByIdOfPartner (id: string, spMchId: string, subMchid: string, serialNo: string, privateKey: Buffer | string);getTransactionByOutTradeNoOfPartner (outTradeNo: string, spMchId: string, subMchid: string, serialNo: string, privateKey: Buffer | string);refundOfPartner (refund: RequireOnlyOne<RefundParametersOfPartner, 'transaction_id' | 'out_trade_no'>, spMchId: string, serialNo: string, privateKey: Buffer | string);getRefundOfPartner (outRefundNo: string, spMchId: string, subMchId: string, serialNo: string, privateKey: Buffer | string);refundedCallbackOfPartner (certs: Map<string, string>, apiKey: string, req: Request, res: Response): Promise<RefundNotifyResultOfPartner>;createCardTemplateOfPartner (data: CreateCardTemplateRequestOfPartner, spMchId: string, serialNo: string, privateKey: Buffer | string);fapiaoDevConfigOfPartner (data: DevelopmentConfigRequestOfPartner, spMchId: string, serialNo: string, privateKey: Buffer | string);getFapiaoDevConfigOfPartner (spMchId: string, subMchId: string, serialNo: string, privateKey: Buffer | string);fapiaoCallbackOfPartner (certs: Map<string, string>, apiKey: string, req: Request, res: Response): Promise<FapiaoNotifyResultOfPartner>;getUserTitleOfPartner (params: GetUserTitleParams, spMchId: string, subMchId: string, serialNo: string, privateKey: Buffer | string);issueFapiaoOfPartner (data: IssueFapiaoRequestOfPartner, spMchId: string, serialNo: string, privateKey: Buffer | string, platformSerial: string);getIssueFapiaoOfPartner (fapiaoApplyId: string, fapiaoId: string | null | undefined, spMchId: string, subMchid: string, serialNo: string, privateKey: Buffer | string);reverseFapiaoOfPartner (fapiaoApplyId: string, data: ReverseFapiaoRequestOfPartner, spMchId: string, serialNo: string, privateKey: Buffer | string);import { MessageCrypto } from 'nest-wechat';
const sha1 = MessageCrypto.sha1('string to hash');静态方法:
- sha1 (...args: string[]): string;
- md5 (text: string): string;
- getAESKey (encodingAESKey: string): Buffer;
- getAESKeyIV (aesKey: Buffer): Buffer;
- PKCS7Encoder (buff: Buffer): Buffer;
- PKCS7Decoder (buff: Buffer): Buffer;
- decrypt (aesKey: Buffer, iv: Buffer, str: string): string;
- encrypt (aesKey: Buffer, iv: Buffer, msg: string, appId: string): string;
- createNonceStr (length = 16): string;
- encryptMessage (appId: string, token: string, encodingAESKey: string, message: string, timestamp: string, nonce: string): string;
- decryptMessage (token: string, encodingAESKey: string, signature: string, timestamp: string, nonce: string, encryptXml: string);
- decryptMessage (token: string, encodingAESKey: string, signature: string, timestamp: string, nonce: string, encryptXml: string);
- checkSignature (signature: string, timestamp: string, nonce: string, token: string);
Create .env.test.local file, and save your test appid and secret in the file.
TEST_APPID=your/test/appid
TEST_SECRET=your/test/secret
TEST_JSSDK_URL=https://your/website/url
TEST_TOKEN=your/token
TEST_AESKEY=your/aeskey
REDIS_HOST=your/redis/host
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
REDIS_TTL=600
Run e2e test.
npm run test:e2eRun unit test.
npm run test wechat.service.userinfo.spec.ts- 开启服务测试
npx ts-node -T tests/e2e/wechat-app.main.ts-
公众号消息推送配置(微信公众测试平台),开启上面服务测试后,可以通过配置验证
-
URL: http://your/url/wechat/push,如:http://113.22.11.2:3001/wechat/push
-
Token: pamtest
-
在微信公众平台接口调试工具获得access_token
body
{
"grant_type": "client_credential",
"appid": "your/appid",
"secret": "your/secret",
"force_refresh": false
}- 在微信开放平台调试工具-消息推送测试的调试工具测试推送