使用node处理微信小程序的v3支付与支付回调

Node.js的crypto模块 加密 Node.js的crypto模块提供了许多加密和解密功能,包括对称加密、非对称加密、哈希函数等。在本篇文章中,我们将详细介绍Node.js的crypto模块的API、代码注释和举例。 阅读详情

记录一次使用node处理微信小程序的v3支付与支付回调

预付款签名生成

比较不好理解的就是签名怎么生成,理解过后其实也挺简单的。下面代码可以直接使用,某些关键参数使用自己的就可以了。 文档链接

    import { randomBytes, createPrivateKey, sign } from 'crypto'
    import { readFileSync } from 'fs'

    const tradeNo = '' // 根据自己业务逻辑生成订单号
    const openId = '' // 小程序支付用户的openId
    const goodsAmount = 1 // 支付金额:单位分
    const goodsName = 'test支付' // 显示在支付时商品名称
    const mchid = '' // 商户号
    const wxAppid = '' // 小程序appid
    const wxPayHost = 'https://api.mch.weixin.qq.com'
    const wxPayApi = '/v3/pay/transactions/jsapi'
    const apiUrl = wxPayHost + wxPayApi
    // 生成签名
    const generateSignature = (method, url, timestamp, nonce, data) => {
        const key = getWechatPrivateKeyInstance()
        const privateKey = createPrivateKey(key);
        const message = method + '\n' + url + '\n' + timestamp + '\n' + nonce + '\n' + data + '\n';
        const signature = sign('sha256', Buffer.from(message), { key: privateKey }).toString('base64');
        return signature;
    }
    // 读取商户API证书密钥
    const getWechatPrivateKeyInstance = (): Buffer => {
        const merchantPrivateKeyFilePath = 'pem/apiclient_key.pem'; // 证书文件官方后台生成下载
        return readFileSync(resolve(merchantPrivateKeyFilePath));
    }

    // 微信调起支付所需参数,可以参考文档
    const createOrderParams = (money: number, orderName: string, openId: string, tradeNo: string) => {
        return {
            mchid: mchid,
            out_trade_no: tradeNo,
            appid: this.wxAppid,
            description: orderName,
            notify_url: this.notifyUrl,
            amount: {
                total: money,
                currency: 'CNY'
            },
            payer: {
                openid: openId
            }
        }
    }
    // 固定格式
    const getPrepayIdString = (prepay_id: string) => {
        return "prepay_id=" + prepay_id
    }
    const getPaySign = (prepay_id: string)  => {
        const getPrepayIdString = getPrepayIdString(prepay_id)
        const key = getWechatPrivateKeyInstance()
        const privateKey = createPrivateKey(key);
        const nonce = randomBytes(16).toString('hex');
        const timestamp = Math.floor(Date.now() / 1000).toString();
        const message = wxAppid + '\n' + timestamp + '\n' + nonce + '\n' + getPrepayIdString + '\n';
        const signature = sign('sha256', Buffer.from(message), { key: privateKey }).toString('base64');
        return {
            timestamp,
            nonce,
            package: getPrepayIdString,
            signType: 'RSA', // 签名类型,默认为RSA,仅支持RSA
            paySign: signature
        }
    }

    const requestData = createOrderParams(goodsAmount, goodsName, openId, tradeNo) 

    const timestamp = Math.floor(Date.now() / 1000).toString();
    // 获取当前时间戳
    // 生成随机字符串
    const nonce = randomBytes(16).toString('hex');
    // 生成签名
    const signature = await generateSignature('POST', wxPayApi, timestamp, nonce, JSON.stringify(requestData));
    // 构造Authorization头部
    const authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",nonce_str="${nonce}",timestamp="${timestamp}",serial_no="${this.serial}",signature="${signature}"`;

    // 发起微信预付款请求
    axios.post(apiUrl, requestData, {
        headers: {
          'Content-Type': 'application/json',
          'Authorization': this.authorization
        },
      }).then(async res => {
        // 拿到调起支付所需prepay_id
        const prepay_id = res.data.prepay_id

        // 拿到了prepay_id 需要去组串调起支付所需参数
        // https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/mini-transfer-payment.html
        getPaySign(prepay_id)

      })



 以上流程就能够达到调起小程序微信支付的步骤,当微信支付完成过后,微信小程序官方会调用自己项目提供的notify接口以获取微信支付回调

微信支付回调解密处理

import { createPrivateKey } from 'crypto'
// 微信回调解密
const decodePayNotify = (resource: wxPayCallbackBodyType['resource']): wxPayCallbackDecodeType => {
    const v3Key = '' // 微信后台获取 v3 key
    try {
      const { ciphertext, associated_data, nonce } = resource
      const AUTH_KEY_LENGTH = 16
      // 密钥
      const key_bytes = Buffer.from(v3Key, 'utf-8')
      // 随机串
      const nonce_bytes = Buffer.from(nonce, 'utf-8')
      // 填充内容
      const associated_data_bytes = Buffer.from(associated_data, 'utf-8')
      // 密文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 = 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(),
      ]);
      // 解密后 转成 JSON 格式输出
      return JSON.parse(output.toString('utf8'));
    } catch (error) {
      console.log('解密失败', error)
      throw error
    }

  }


// 提供notify接口,需要在微信后台配置回调地址,比如接口地址时:/pay/notify。就需要提供路由为https://xxx/pay/notify的接口给微信调用
const notify = (req) => {
    console.log('微信回调')
    const data: wxPayCallbackBodyType = req?.body || {}

    if (data.event_type === 'TRANSACTION.SUCCESS') {
        const decodeInfo = decodePayNotify(data.resource)
        console.log('支付回调解析数据:', decodeInfo)
    }
}


// 微信回调内容
interface wxPayCallbackDecodeType {
	mchid: string
	appid: string
	out_trade_no: string
	transaction_id: string
	trade_state: string
	trade_state_desc: string
	bank_type: string
	attach: string
	success_time: string
	payer: { openid: string },
	amount: { total: number, payer_total: number, currency: string, payer_currency: string }
}
// 微信回调参数
interface wxPayCallbackBodyType {
	id: string
	create_time: number
	resource_type: string
	event_type: string
	summary: string
	resource: {
		original_type: string
		algorithm: string
		ciphertext: string
		associated_data: string
		nonce: string
	}
}

至此,微信小程序支付比较关键的预付款加密和回调解密都正常走通啦。当然还有一些其他逻辑,比如超时的预付款订单需要主动触发微信关闭订单接口,在此就不演示了。

文章转自:https://juejin.cn/post/7372377436464791578

【愚公系列】《微信小程序开发解析》018-小程序支付 随着移动支付的兴起,小程序作为一种新型的应用形式,已成为商家和开发者实现在线交易的重要平台。微信小程序支付功能的强大便捷,不仅提升了用户的购物体验,也为商家创造了更多的商业机会。因此,了解小程序支付相关知识点,对于开发者和商家而言显得尤为重要。本文将系统介绍小程序支付的基本概念和实现方式,涵盖支付流程、接口使用及注意事项等关键内容。我们将详细讲解如何接入微信支付、如何处理支付结果以及常见的支付异常处理方式,并结合实际案例,帮助您更好地理解和应用这些知识。 阅读详情

相关推荐

微信小程序支付-多商户号绑定切换实战

做过电商类小程序的朋友应该都遇到过这样的场景:你的平台上有多个商家入驻,每个商家都需要独立的收款账户。这时候如果只绑定一个微信支付商户号,所有钱都会进到同一个账户,后续分账会非常麻烦。我去年接手的一个生鲜电商项目就踩过这个坑——最初只接了一个商户号,结果每天要对账到凌晨两点。最近在给一个连锁品牌做支付系统升级,他们300多家门店各自需要独立商户号。关键是要在数据库设计阶段就考虑好多租户的场景,避免后期重构。特别提醒:如果小程序主体和商户号主体不一致,需要额外准备《联合运营承诺函》。遇到过审核被拒的情况?

weixin_34116110的博客 730

Node——微信支付 V3接口

【代码】Node——微信支付 V3接口。

qq812457115的博客 1523

避坑指南:微信小程序第三方支付常见错误及解决方案

本文深度剖析微信小程序第三方支付接入中的常见陷阱解决方案,重点聚焦密钥配置、签名验证、支付回调处理等核心环节。通过实战代码示例排查清单,帮助开发者系统性地规避支付失败风险,确保从“支付失败”到“收款成功”的流程稳定可靠。

tgb34567890的博客 1001

node】实现微信支付 apiv3(wechat-node-v3库)

node中实现微信支付apiv3接口的使用,主要用到的库是wechat-node-v3使用,附上代码!

m0_53166050的博客 2940

Nodejs实现微信小程序支付功能前后端实践 全新的微信支付 APIv3

自己实现一个带支付功能的小程序,前端使用uniapp,后端使用Node.js,将实现微信小程序支付功能的全流程详细记录下来。使用的是全新的微信支付 APIv3,优点是 -使用JSON作为数据交互的格式,不再使用XML。

html0010的博客 4444

Node.js关于微信支付V3版相关处理方法

今天给大家写一个关于Node.js接入微信支付V3接口时一些毕竟复杂的点,主要就是请求签名Authorization、调起支付签名、回调参数解密等。请求签名Authorization在微信支付V3接口中,商户需要使用自身的私钥对API URL、消息体等关键数据的组合进行SHA-256 with RSA签名。请求的签名信息通过HTTP头Authorization传递,具体说...

小创果技术交流博客 4442

关于使用nodejs搭建微信小程序支付接口

nodejs项目成功部署到服务器之后,我们只需要在微信小程序先对https://域名/pay 发起get请求拿到数据后再调用wx.requestPayment即可发起支付。最后,祝您玩的愉快!

qq_34179819的博客 2332

Node.js】实现微信小程序在线支付功能

node.js实现微信小程序在线支付功能

业余丰富各种技术栈 3464

微信小程序对接微信支付

本文系统讲解了微信小程序对接微信支付的完整开发流程,包括准备工作、后端统一下单、小程序调起支付回调处理工程化封装。结合实际开发经验,详细展示了每个模块的设计代码实现,避免常见问题坑点。通过模块化封装规范化开发思路,帮助开发者快速搭建稳定、高效的小程序支付功能,提升支付体验业务转化效率。适合所有需要集成微信支付小程序项目参考使用

qq_40791475的博客 6504

wechatpay-node-v3-ts完全指南:微信支付V3接口在TypeScript/JavaScript中的终极实践

想要在Node.js项目中轻松集成微信支付V3接口吗?wechatpay-node-v3-ts正是您需要的终极解决方案!这个专业的微信支付V3 SDK让TypeScript和JavaScript开发者能够快速、安全地接入微信支付功能。无论您是电商平台开发者、SaaS服务提供商,还是独立开发者,这个库都能为您提供完整的微信支付V3接口支持。🚀 ## 📦 项目概览核心优势 wechatpay

gitblog_00532的博客 1057

微信小程序支付之V2支付

微信小程序支付--v2

qq_30272167的博客 2496

微信小程序接入微信支付全流程指南(CloudBase / JSAPI / 真机可用)

计算 Authorization,请求 https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi。:配置“支付结果通知 URL”为 https://<cloudbase-domain>/pay/wechat/notify。拿到 prepay_id 后,生成前端 timeStamp/nonceStr/package/paySign 返回。浏览器访问 https://<云开发域名>/pay/wechat/notify,看到 JSON 即通。

patrictstar的博客 1765

Java微信小程序支付

微信开发中经常使用微信支付,那么此篇文章将告诉您如何完成微信支付,以下内容以小程序支付为例 导入依赖 <dependency> <groupId>org.apache.directory.studio</groupId> <artifactId>org.apache.commons.codec</artifactId> <version>1.8</version> </dependency.

RickSunLee的博客 949

微信小程序后端开发完整Demo实战:OpenID获取微信支付集成

随着移动互联网的快速发展,微信小程序凭借其“即用即走”的轻量级特性,已成为企业构建线上服务的重要入口。在众多功能中,用户身份识别支付能力是核心业务场景的关键支撑。因此,构建一个安全、稳定、可扩展的小程序后端系统至关重要。本章将从整体视角出发,介绍微信小程序后端的基本架构模型,涵盖前端后端的通信机制、微信官方API的调用流程以及典型的技术栈选型方案。

weixin_28681379的博客 1171

TNWX 从入门到精通:微信支付功能集成完整教程,附企业级代码示例

TNWX 是基于 TypeScript 和 Node.js 的微信系开发脚手架,支持微信公众号、微信支付微信小程序等多种场景,能快速集成到 Express、Nest、Egg 等任意 Node.js 框架中。本文将带您完整掌握 TNWX 微信支付功能的集成方法,从环境搭建到企业级代码实践,让您轻松实现微信支付功能。 ## 一、TNWX 微信支付模块核心架构 TNWX 采用模块化设计,微信支付

gitblog_00281的博客 602

记录一下使用node对接微信支付签名的问题

用来各种签名方法,md5,crypto都失败了 等后续有时间了在排查问题。才发现自己的小程序还是个人账户 不具备支付能力。目前正在申请中 后续接入微信支付了在来回补。通过postman调用获取支付参数。回顾一下之前自己构造签名的失败经历。这里贴上部分实现构造签名的代码。

月色真美121的博客 691

微信支付】三步搞定内网穿透,本地调试微信支付回调

本文针对微信支付本地调试中回调通知无法接收的难题,提出使用内网穿透工具natapp的三步解决方案。通过获取Authtoken、运行客户端建立隧道、配置微信支付回调URL,开发者可在本地IDE中实时接收并调试支付结果通知,极大提升开发测试效率。

weixin_29202213的博客 153
上一篇: JS实现class的私有属性
下一篇: 小众 CSS 新特性
前端77
博客等级 码龄2年 2862粉丝 · 306原创
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值