npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

wechat-pay-v3

v2.2.9

Published

Wechat Pay V3 SDK for Node.js

Downloads

89

Readme

微信支付 V3SDK

  • 🛠️ 极易扩展

  • 🛠️ typescript 编写且类型完备

  • 🛠️ 自动更新平台证书

  • 🛠️ 支持直连商户体系和服务商体系

  • 🛠️ hook 请求过程

安装

项目使用了 node 自身的 crypto,请确保运行的版本大于 15.6

npm install wechat-pay-v3

说明

sdk 公开工具函数,基础类和功能类。工具函数针对应用场景代码封装,基础类是 sdk 的核心,功能类为具体的功能实现。实现的功能类列表可在下方表格中查看。

base 类提供了验签方法resVerify,但并没有给功能方法添加自动验签。除了封装的 handleCallback 方法,其他情况下您可以通过 hook 的方式在 onResponse 中进行验签,下方有实例代码。

大多数情况下,提供的方法对于加密参数都是自动的,部分过于复杂的接口,在 JSDOC 提示中会有 notAutoEncrypt 标注。

使用

hook

请求流程:[onRequsetBefore] -> [sdkWork] -> [onRequsetAfter] -> [onResponse]

hook 方法传递的参数都是原始引用,请注意不要轻易修改,除非你知道你在做什么。

sdkWork:为请求的核心逻辑,在这个阶段会对参数进行加密,签名,更新证书等操作。

apiController(
  {
    /* config */
  },
  {
    onRequsetBefore(config, instance) {
      console.log(config)
    },
    onRequsetAfter(config, instance) {
      console.log(config)
    },
    onResponse(res, instance) {
      console.log(res)
      //如果需要验签
      const verifyResult = instance.resVerify(res.headers, res.data)

      //部分接口是不需要验签的,不要轻易直接抛错
      //您可以将验签结果加入 res.data 中,大多数方法返回res.data
      res.data.verifyResult = result
    },
  },
)

//or

const base = new WechatPayV3Base(
  {
    /* config */
  },
  {
    /* hooks */
  },
)

调用方式

调用方式有两种,一种通过封装的容器调用,一种通过类调用。容器实现默认单例(容器调用的类均单例)和自动的依赖注入。 容器函数为apiController

import { apiController, ContainerOptions, Applyment } from 'wechat-pay-v3'
const Config: ContainerOptions = {
  //证书
  apiclient_cret: readFileSync('/xx/apiclient_cret.pem'),
  //证书密钥
  apiclient_key: readFileSync('/xx/apiclient_key.pem'),
  //后台配置的key
  apiV3Key: 'APIv3密钥',
  //商户号
  mchid: '商户号',
  //默认单例模式,开启后同个商户号只会返回一个实例。
  singleton: true,
  //可选:默认系统的tmp目录
  downloadDir: './tmpDownlond',
  //可选: 默认ture。开启后会缓存证书12小时,12小时后惰性更新证书
  autoUpdateCertificates: true,
  //可选,默认'wechatpay-sdk'
  userAgent: 'wechatpay-nodejs-sdk/1.0.0',
}
//1 容器获取示例
const applyment = apiController(Config).use(Applyment)
//2 类直接new就好,不过请自行管理实例避免重复创建造成性能浪费
const applyment = new Applyment(new WechatPayV3Base(Config))
//Applyment 为特约商户的功能类
//上方两种方式都可以拿到 applyment 实例
//例如调用提交特约商户申请接口
applyment.submitApplications()

已实现功能

| 功能 | 官方链接 | 库名 | 服务商 | 直连商户 | | ----------- | ------------------------------------------------------------------------------------ | --------------- | ------ | -------- | | 核心类 | 加解密,管理证书,扩展功能使用的基础类 | WechatPayV3Base | √ | √ | | 特约商户 | link | Applyment | √ | | | 基础支付 | 因除合单支付外,其余方式仅下单不同,BasePay 为支付基类 | BasePay | √ | √ | | JSAPI 支付 | link | JSPay | √ | √ | | 小程序支付 | link | MiniProgramPay | √ | √ | | APP 支付 | link | AppPay | √ | √ | | H5 支付 | link | H5Pay | √ | √ | | Native 支付 | link | NativePay | √ | √ |

sdk 满足大多数情况下的基本支付功能.扩展其余功能请参考扩展功能类

TODO

  • [ ] 国密支持

核心类

  • hook 事件 setEvents
  • 证书相关
    • 获取证书 getCertificates
    • 更新证书 updateCertificates
  • 请求相关
    • 请求实例 request
    • 下载文件 downloadFile
    • 上传图片 uploadImage
    • 上传视频 uploadVideo
  • 加解密
    • 公钥加密 publicEncrypt
    • 公钥加密(批量) publicEncryptObjectPaths
    • AESGCM 解密 aesGcmDecrypt
    • SHA256 签名 sha256WithRSA
    • SHA256 验签 sha256WithRsaVerify
  • 常用封装
    • 响应验签 resVerify
    • 回调处理 handleCallback

示例代码

下单接口示例

const router = Router()
const appId = '小程序appid'
const wxpay = router.post('/pay/order', async (req, res, next) => {
  try {
    const miniPay = apiController({
      /* xxx */
    }).use(MiniProgramPay)
    const { prepay_id } = await miniPay.order({
      /* xxx */
    })
    //获取小程序支付参数
    const payParams = miniPay.getPayParams({
      appId,
      prepay_id,
    })
    /* 小程序可以调起支付直接传入payParams即可 */
    res.send(payParams)
  } catch (e) {
    next(e)
  }
})

通知接收

base 实例上封装了通用的 handleCallback,他的功能是进行回调验签,通过后返回的 resource 对象会自动解密。

import { apiController } from 'wechat-pay-v3'

//假定这里是一个接口
router.post('/notify', async (req, res) => {
  try {
    const wxapi = apiController({
      /* xxx */
    })
    //handleCallback接收两个参数,第一个是请求头,第二个是请求体。
    //实际并不一定是这样的,请根据实际情况调整。
    const data = await wxapi.handleCallback(req.headers, req.body)
    res.status(204).send()
  } catch (e) {
    res.status(400).send({
      message: e.message,
      code: 'FAIL',
    })
  }
})

扩展功能类

封装 sdk 的目的是解决现有项目的需求,所以优先保证的是架构的扩展性,而非接口完整。

当你遇到 sdk 未提供的接口时,可以注入 WechatPayV3Base 实例来完成。

import { WechatPayV3Base } from 'wechat-pay-v3'

class Others {
  //将WechatPayV3Base实例作为依赖
  constructor(public base: WechatPayV3Base) {}

  async test() {
    //调用base的request进行请求.自动签名满足大多数情况下的请求.
    //如果签名串并非data对象的内容,请自行计算
    //可以参照源码中_upload的实现
    return this.base.request({
      url: 'https://xxx.xxx.xxx/xxx', //需要为完整的url而非接口路径
      method: 'GET',
    })
  }
}

const baseIns = new WechatPayV3Base({
  /* xxx */
})
const others = new Others(baseIns)
//直接调用
others.test()
//或者通过容器调用
apiController({
  /* xxx */
})
  .use(Others)
  .test()

贡献须知

  • 类型和 JSDOC 完整
  • 请求一律返回 data 且描述好 data 的类型,这样取值能看到是个啥,而非把具体值返回去
    • 如果返回的数据没有 data,例如根据状态码返回成功与否的情况返回 boolean 且描述出来
  • 命名规范
    • 直连商户命名直接使用具体方法做名称,例如:order
    • 服务商命名使用 [方法名]OnProvider,例如:orderOnProvider
  • 直连和服务商的方法分开,不要 类型或来书写,因为 typescript 提示不会缩减范围导致类型提示错误(函数重载也可以实现功能,不过我选择了分开,这样更加清晰)
  • 由于直连商户和服务商的调用参数往往不一样,调用参数统一全量填写,而非引用配置的方式。这样可以保证参数的正确性。例如需要 mchid 和 openid,那么就需要传入 mchid 和 openid,而不是引用配置的 mchid。