1. 准备环节
// 这些都需要在微信后台自行申请,[微信开发者平台](https://mp.weixin.qq.com)
appid:string // 小程序ID
mchid:string // 商户号
apiclient_cert.pem // 公钥
apiclient_key.pem // 秘钥
v3 // 微信支付结果的解密密钥, 需要在开发者平台自行设置
需要这两个与支付相关的依赖库 wechatpay-node-v3
, nest-wechatpay-node-v3
yarn add wechatpay-node-v3 nest-wechatpay-node-v3
2.支付流程
2.1 登录
这里我们就不细说了,不会可以自行百度.登录完成之后,小程序会拿到当前微信用户的uuid, openid
2.2 小程序发起一个预支付请求,请求nestjs后台接口
// 小程序端请求参数
const options = {
appid: 'xxx', // 小程序appid
payer: uuid, // 微信账号的uuid
openid: openid, // 微信账号的uuid
amount: '', // 支付金额
orderNo:'3123123123' // 关于这个订单编号, 保证唯一即可,这里选择前端生成, 也可后端生成,商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。 特殊规则:最小字符长度为6,
description: '这是一段支付描述',
}
// 请求nestjs后台接口拿到相关参数调起微信支付
const res = wx.request(url, method, options)
wx.requestPayment({
provider: 'wxpay', //支付类型-固定值
timeStamp: res.data.timeStamp, // 时间戳(单位:秒)
nonceStr: res.data.nonceStr, // 随机字符串
package: res.data.package, // 固定值
signType: res.data.signType, //固定值
paySign: res.data.paySign, //签名
success: function (res) {
// 支付成功
},
fail: function (err) {
// 支付失败
},
})
// NestJs后台
payment.module.ts
import { WeChatPayModule } from 'nest-wechatpay-node-v3'
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
// 这里配置一下
WeChatPayModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (config: ConfigService) => {
return {
appid: '直连商户申请的公众号或移动应用appid',
mchid: '商户号',
publicKey: fs.readFileSync('./apiclient_cert.pem'), // 公钥
privateKey: fs.readFileSync('./apiclient_key.pem'), // 秘钥
}
}
}),
]
})
payment.service.ts
import WxPay from 'wechatpay-node-v3'
import { WECHAT_PAY_MANAGER } from 'nest-wechatpay-node-v3'
@Injectable()
export class PaymentService {
constructor(
@Inject(WECHAT_PAY_MANAGER)
private readonly wxPay: WxPay,
) { }
async prePayment(params:ParmentDto){
//这里的params就是小程序传递的相关参数
const { appid, payer, openid, description, amount, orderNo } = params
const Fen = this.convertYuanToFen(Number(amount)) // 这里通过一个函数把钱转化为以分为单位的数字
const options = {
appid,
mchid: '商户号',
description,
out_trade_no: orderNo,
notify_url: '支付完成后微信将通过这个接口返回给你支付结果,必须保证是一个公网的域名,如:http://baidu.com/notify',
amount: {
total: Fen, // 转化后的数据
},
payer: {
openid
}
}
// TODO: 这里省略了将这条支付订单保存到数据库的步骤,请读者自行编写
const res = await this.wxPay.transactions_jsapi(options) // 请求微信官方服务器
return res // 这个res中就包含了小程序调起微信支付的相关参数
}
// 当微信官方收到上面的数据,将多次调用notify_url,将支付信息传递过来
@Post()
async notify_url(@Body() body: WxNotifyDto){
// 这个body中是更私密的支付信息,我们通过解密之后才能拿到
const v3 = '........' // 解密密钥
const { resource } = body
const { ciphertext, associated_data, nonce } = resource
// out_trade_no 这个数据就是我们自行生成的支付的订单编号,可以根据这个查到此次支付信息
const { out_trade_no } = await this.wxPay.decipher_gcm<TransactionResource>(ciphertext, associated_data, nonce, v3)
// TODO: 需要根据返回的不同支付状态调整订单的支付状态
// 到这里支付就算是完成了
}
}