微信支付链路+封装对接微信API工具类(下)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 微信支付链路+封装对接微信API工具类(下)

封装获取微信平台证书列表+解密得到微信公钥

wx回调本地地址时使用wx证书的公 钥进行解密。

WxPayment
    //验证签名 timestamp,nonce,serial,signature均在HTTP头中获取,body为请求参数
    async verifySign({ timestamp, nonce, serial, body, signature }) {
        // 拼接参数
        let data = `${timestamp}\n${nonce}\n${typeof body == 'string' ? body : JSON.stringify(body)}\n`;
        // 用crypto模块解密
        let verify = crypto.createVerify('RSA-SHA256');
        // 添加摘要内容
        verify.update(Buffer.from(data));
        // 从初始化的平台证书中获取公钥
        for (let cert of this.certificates) {
            if (cert.serial_no == serial) {
                return verify.verify(cert.public_key, signature, 'base64');
            } else {
                throw new Error('平台证书序列号不相符')
            }
        }
    }
       //解密证书列表 解出CERTIFICATE以及public key
    async decodeCertificates() {
        let result = await this.getCertificates();
        if (result.status != 200) {
            throw new Error('获取证书列表失败')
        }
        let certificates = typeof result.data == 'string' ? JSON.parse(result.data).data : result.data.data
        for (let cert of certificates) {
            let output = this.dec ode(cert.encrypt_certificate)
            cert.decrypt_certificate = output.toString()
            let beginIndex = cert.decrypt_certificate.indexOf('-\n')
            let endIndex = cert.decrypt_certificate.indexOf('\n-')
            let str = cert.decrypt_certificate.substring(beginIndex + 2, endIndex)
            // 生成X.509证书
            let x509Certificate = new x509.X509Certificate(Buffer.from(str, 'base64'));
            let public_key = Buffer.from(x509Certificate.publicKey.rawData).toString('base64')
            // 平台证书公钥
            cert.public_key = `-----BEGIN PUBLIC KEY-----\n` + public_key + `\n-----END PUBLIC KEY-----`
        }
        return this.certificates = certificates
    }
    //解密
    decode(params) {
        const AUTH_KEY_LENGTH = 16;
        // ciphertext = 密文,associated_data = 填充内容, nonce = 位移
        const { ciphertext, associated_data, nonce } = params;
        // 密钥
        const key_bytes = Buffer.from(this.apiv3_private_key, 'utf8');
        // 位移
        const nonce_bytes = Buffer.from(nonce, 'utf8');
        // 填充内容
        const associated_data_bytes = Buffer.from(associated_data, 'utf8');
        // 密文Buffer
        const ciphertext_bytes = Buffer.from(ciphertext, 'base64');
        // 计算减去16位长度
        const cipherdata_length = ciphertext_bytes.length - AUTH_KEY_LENGTH;
        // upodata
        const cipherdata_bytes = ciphertext_bytes.slice(0, cipherdata_length);
        // tag
        const auth_tag_bytes = ciphertext_bytes.slice(cipherdata_length, ciphertext_bytes.length);
        const decipher = crypto.createDecipheriv(
            'aes-256-gcm', key_bytes, nonce_bytes
        );
        decipher.setAuthTag(auth_tag_bytes);
        decipher.setAAD(Buffer.from(associated_data_bytes));
        const output = Buffer.concat([
            decipher.update(cipherdata_bytes),
            decipher.final(),
        ]);
        return output;
    } 

封装验证微信发起的签名+解密数据得到用户订单信息

开发微信服务器回调接口

  callback: async (req) => {
    let timestamp = req.header('Wechatpay-Timestamp')
    let nonce = req.header('Wechatpay-Nonce')
    let serial = req.header('Wechatpay-Serial')
    let signature = req.header('Wechatpay-Signature')
    let body = req.body
    // 1.校验收到的请求是否来自微信服务器和平台证书是否一致
    let result = await payment.verifySign({
      timestamp,
      nonce,
      serial,
      signature,
      body
    })
    if (!result) {
      return
    }
    // 2.解密body中的数据,拿到用户订单信息
    let bufferoOne = payment.decode(body.resource)
    let json = JSON.parse(bufferoOne.toString('utf8'))
    let { out_trade_no, trade_state } = json
    console.log(json)
    if (trade_state === 'SUCCESS') {
      // 3.根据微信服务器返回的订单信息更新数据库中改订单的支付状态
      await DB.ProductOrder.update({ order_state: 'PAY' }, { where: { out_trade_no } })
      // 4.更新redis课程热门排行榜数据
      let productItem = await DB.ProductOrder.findOne({ where: { out_trade_no }, raw: true })
      let memberInfo = {
        id: productItem.product_id,
        title: productItem.product_title,
        img: productItem.product_img,
      }
      let time = dayjs(Date.now()).format('YYYY-MM-DD')
      await redisConfig.zincrby({ key: `${time}:rank:hot_product`, increment: 1, member: JSON.stringify(memberInfo) })
    }
    return BackCode.buildSuccess()
  },

这里redis的逻辑是

  1. DB.ProductOrder.findOne({ where: { out_trade_no }, raw: true }): 这是一个数据库查询操作,通过out_trade_no作为查询条件,在ProductOrder表中查找匹配的记录,并返回一个包含产品项信息的对象。raw: true选项表示返回原始数据,而不进行模型实例化。
  2. 接下来,将产品项的信息存储到memberString对象中,包括产品的 ID、标题和图片。
  3. dayjs(Date.now()).format('YYYY-MM-DD'): 这行代码使用了第三方库 dayjs,用于获取当前日期并以 'YYYY-MM-DD' 的格式进行格式化。生成的日期字符串被存储在time变量中。
  4. redisConfig.zincrby({ key: {time}:rank:hot_product, increment: 1, member: JSON.stringify(memberString) }): 这是一个使用 Redis 的命令,通过zincrby方法向 Redis 的有序集合中更新数据。key参数表示要更新的有序集合的键名,这里使用了{time}:rank:hot_product作为键名;increment参数表示每次增加的分值,这里设置为 1;member参数表示要添加或更新的成员,将前面存储的产品项信息以 JSON 字符串的形式作为成员。

每天凌晨清除昨天的数据

定时插件

yarn add node-schedule@2.1.0

配置

// 定时任务工具
const schedule = require('node-schedule')
let rule = new schedule.RecurrenceRule()
class ScheduleTool {
  // 每天凌晨0点执行
  static dayJob(handle) {
    rule.hour = 0
    schedule.scheduleJob(rule, handle)
  }
}
module.exports = ScheduleTool

定时任务执行

ScheduleTool.dayJob(() => {
  let yesterday = dayjs().subtract(1, 'day').format('YYYY-MM-DD')
  redisConfig.del(`${yesterday}:rank:hot_product`)
})

我们要拿到的就是body.resource

image.png

pay.weixin.qq.com/wiki/doc/ap…

订单状态确认-查询订单⽀付状态逻辑封装+快速验证

node服务器主动进行接口调用查询订单

查询订单逻辑封装

//通过out_trade_no查询订单
async getTransactionsByOutTradeNo(params) {
  return await this.wxSignRequest({ pathParams: params, type: 'getTransactionsByOutTradeNo' })
}

验证订单状态查询

const { payment } = require('./config/wechatPay');
(async () => {
    let wechatOrder = await payment.getTransactionsByOutTradeNo({ out_trade_no: '123456789wqjeqjwdiqhdhqd' })
    console.log(wechatOrder.data)
})()
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
2月前
【微信公众平台对接】有关【创建发票卡券模板】调用示例
【微信公众平台对接】有关【创建发票卡券模板】调用示例
16 0
|
2月前
【微信公众平台对接】有关【上传图文消息内的图片获取URL】调用示例
【微信公众平台对接】有关【上传图文消息内的图片获取URL】调用示例
48 0
|
2月前
【微信公众平台对接】有关上传pdf到微信
【微信公众平台对接】有关上传pdf到微信
22 0
|
9天前
|
人工智能 机器人 API
【Python+微信】【企业微信开发入坑指北】3. 如何利用企业微信API给微信群推送消息
【Python+微信】【企业微信开发入坑指北】3. 如何利用企业微信API给微信群推送消息
12 0
|
9天前
|
缓存 人工智能 API
【Python+微信】【企业微信开发入坑指北】2. 如何利用企业微信API主动给用户发应用消息
【Python+微信】【企业微信开发入坑指北】2. 如何利用企业微信API主动给用户发应用消息
9 0
|
16天前
|
SQL 缓存 测试技术
API接口对接中需要注意的问题(4)
有几个关键的问题需要注意,它们涉及安全性、性能、数据一致性和错误处理等方面
|
22天前
|
JSON 监控 API
在API接口对接中关键示例问题(1)
在API接口对接中,有几个关键的问题需要注意,以确保接口的稳定性、安全性和易用性。以下是这些问题及部分示例代码的简要概述
|
2月前
|
JSON Java API
微信支付JSAPI3微信支付开发API V3
微信支付JSAPI3微信支付开发API V3
25 0
|
2月前
|
人工智能 JavaScript API
互联网人的福利!『昆仑天工』4款AI产品开源!提供API对接!
互联网人的福利!『昆仑天工』4款AI产品开源!提供API对接!
195 0
|
3天前
|
存储 缓存 运维
DataWorks操作报错合集之DataWorks根据api,调用查询文件列表接口报错如何解决
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
12 1