微信支付作为中国最流行的移动支付方式之一,在微信小程序中集成微信支付功能可以极大的提升用户体验和业务转换率。那么如何在微信小程序实现微信支付的功能呢?(该文章通过nodejs接入,其他编程语言接入的步骤也是一样的哦!)请看下文步骤:
源码地址:【免费】微信小程序支付-nodejs框架demo资源-CSDN文库
首先,你应该提前准备好对应的接入资料,并且仔细阅读官方文档哈!那么要准备啥呢?
1. 准备好你的商户号和证书序列号
- 商户号在这里看:进入商户平台——头部导航栏点击账户中心——点击左边的商户信息——就能看到啦!
- 证书序列号在这里看:进入商户平台——头部导航栏点击账户中心——点击左边的API安全——管理证书——证书序列号
2. 准备好你的小程序AppID和AppSecret:进入微信公众平台,选择你的小程序登录!
3. 将商户号和小程序AppID进行关联。先去商户平台输入小程序AppID,再回去小程序确认。
准备好资料就可以进入开发阶段啦,自己准备好NodeJS的开发环境哦!!!
第一步:进入根目录,打开终端输入npm i axios cors dotenv express,安装我们开发所需要的依赖包。
- axios:用于发起HTTP请求,与微信官方服务器进行交互;
- cors:实现跨域资源共享;
- dotenv:提供环境变量加载功能,从.env文件中加载环境变量;
- express:NodeJS框架,用于搭建服务器端应用。
第二步:在根目录新建.env,将准备好的资料放入,以便开发使用。
第三步:将你申请的证书公钥和密钥放入根目录或者其他地方。
第四步:搭建服务器,并获取openid,openid用于识别支付者是谁。
- 搭建服务器,在根目录新建一个router文件夹和serve.js文件,router文件夹里在新建一个wxlogin.js文件,然后编写代码。
// serve.js
// 导入express模块
const express = require('express')
// 创建服务器对象
const serve = express()
// 开启跨域
const cors = require('cors')
serve.use(cors())
// 导入微信登录模块并注册使用
const wechatLogin = require('./router/wxlogin')
serve.use('/api',wechatLogin)
// 启动服务器
serve.listen('5000',()=>{
console.log('http://127.0.0.1:5000')
})
// wxlogin.js
// 引入express框架
const express = require('express')
// 创建express的Router实例
const router = express.Router()
// 引入dotenv库,用于加载环境变量
require('dotenv').config()
// 引入axios库,用于发送HTTP请求
const axios = require('axios')
// 从环境变量中获取微信小程序的应用id和密钥
const { APP_ID, APP_SECRET } = process.env
// 微信登录接口
router.post('/login', async (req, res) => {
try {
// 从请求查询参数中获取code
const { code } = req.query
// 换取openid接口的URL
const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${APP_ID}&secret=${APP_SECRET}&js_code=${code}&grant_type=authorization_code`
// 发送GET请求到微信接口,获取openid
const { data: { openid } } = await axios.get(url)
console.log(openid)
// 响应登录成功消息
res.status(200).send({message: '登录成功'})
} catch (err) {
// 异常情况下响应登录失败消息
res.status(500).send({message:'登录失败'})
}
})
// 导出router对象
module.exports = router
- 编写完代码后,记得启动服务器!!!终端输入node serve.js 。
- 在你正在开发的微信小程序应用中,使用微信登录获取code并向后端服务器发送你的code以换取openid信息。
// index.wxml:
// <view class="box">
// <button class="login" bind:tap="loginHandle">微信登录</button>
// <button class="pay" bind:tap="payHandle">微信支付</button>
// </view>
// index.js
Page({
// 处理微信登录的函数
loginHandle(){
// 调用微信登录接口
wx.login({
success: (res) => {
// 调用成功,res里会返回code
console.log(res)
// 使用获取到的code发起请求,向后端获取用户的openid
wx.request({
url: `http://127.0.0.1:5000/api/login?code=${res.code}`, // 后端接口地址
method:'POST', // 请求方法post
})
},
})
},
})
- 点击登录,服务器将向微信官方服务器发送请求,获取openid(项目开发的话,一般会保存起来,这里演示就直接拿来用了)。
第五步:了解发起微信支付。根据微信官方文档,发起支付前,我们需要构建请求体参数和请求头参数。具体参数看官方文档。
- 请求体必须参数为以下内容:
- 请求头参数需要构造时间戳,随机字符串,然后进行请求签名串构造,并计算签名值,最终发送给请求头。
- 这是签名认证的文档:请求参数里带Path参数(路径参数),如何计算签名 - 通用规则 | 微信支付商户文档中心 (qq.com)
- 当用户调起微信支付,后端会向微信官方请求得到发起支付的必要参数prepay_id,然后我们又又又要构造成指定的内容返回给前端,前端调起微信支付的API,进行支付!!!
第六步:在router文件夹里新建wxpay.js文件,并重新启动服务器。前端调用微信支付,发起支付请求!
// wxpay.js
// 引入express框架
const express = require('express')
// 创建express的Router实例
const router = express.Router()
// 引入dotenv库,用于加载环境变量
require("dotenv").config()
// 引入axios库,用于发送HTTP请求
const axios = require('axios')
// 导入crypto库,用于加密操作
const crypto = require('crypto')
// 导入fs库,用于读取私钥
const fs = require('fs')
// 读取私钥
const privateKey = fs.readFileSync('./apiclient_key.pem', 'utf8')
// 从环境变量中获取应用ID,商户ID,证书序列号
const { APP_ID, MCH_ID, SERIAL_NO } = process.env
// 生成请求随机串
const nonceStr = crypto.randomBytes(16).toString('hex').slice(0, 32)
// // 生成时间戳函数
const generateTimestamp = () => {
return Math.floor(Date.now() / 1000).toString();
}
// 生成签名串函数
const generateSignatureString = (...options) => {
return options.join('\n') + '\n'
}
// 微信支付接口
router.get('/wxPay', async (req, res) => {
// 可以获取前端发送过来的订单ID进行订单查询
// 然后将请求参数的信息修改即可
try {
// 请求参数
const body = {
appid: APP_ID, // 应用ID
mchid: MCH_ID, // 商户ID
description: '测试', // 商品描述
out_trade_no: '1122321322', // 商户订单号
notify_url: 'http://127.0.0.1:3000/api/wxpay/notify', // 回调地址
amount: { // 支付金额
total: 0.01 * 100,
currency: 'CNY'
},
payer: {
openid: 'oQ5V-7YibgnTkj8E2BDE6P48tDKo' // 支付者 openid
}
}
// 生成时间戳
const timeStamp = generateTimestamp()
// 生成签名串
const generateSignature = generateSignatureString('POST', '/v3/pay/transactions/jsapi', timeStamp, nonceStr, JSON.stringify(body))
// 使用私钥签名
const signature = crypto.createSign('RSA-SHA256').update(generateSignature).sign(privateKey, 'base64')
// 构造Authorization头
const authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${MCH_ID}",nonce_str="${nonceStr}",signature="${signature}",timestamp="${timeStamp}",serial_no="${SERIAL_NO}"`
console.log(authorization);
// 发起支付请求
const result = await axios.post('https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi',
body,
{
headers: {
Authorization: authorization
}
})
console.log(result.data)
// 构造订单详情扩展字符串
const package = 'prepay_id=' + result.data.prepay_id
// 构造支付签名串
const paySignStr = generateSignatureString(APP_ID, timeStamp, nonceStr, package)
// 计算支付签名
const paySignsignature = crypto.createSign('RSA-SHA256').update(paySignStr).sign(privateKey, 'base64')
// 返回支付信息
return res.status(200).send({
message: '操作成功',
data: {
appId: APP_ID, // 应用ID
timeStamp, // 时间戳
nonceStr, // 请求随机串
package, // 订单详情扩展字符串
signType: 'RSA', // 签名类型
paySign: paySignsignature // 支付签名
}
})
} catch (err) {
// 处理异常
console.log(err)
return res.status(500).send({ message: '支付失败' })
}
})
// 导出路由模块
module.exports = router
- 在sever.js添加微信支付的路由,并重启服务器
- 微信小程序向后端发起请求,将得到发起支付的必要参数prepay_id。
// 微信小程序
// 微信支付的函数
payHandle() {
// 向后端发起请求,获取微信支付所需的参数
wx.request({
url: 'http://127.0.0.1:5000/api/wxPay', // 后端微信支付接口地址
method: 'GET', // 请求方法为GET
success: (res) => {
console.log(res.data)
// 使用返回的数据进行微信支付
wx.requestPayment({
...res.data.data, // 将后端返回的支付参数展开
success: (payRes) => {
// 支付成功后的回调
console.log(payRes)
}, fail: (payErr) => {
// 支付失败后的回调
console.error(payErr)
}
})
}
})
}
第七步:最后后端构建返回前端发起支付的必要参数,前端使用wx.requestPayment完成支付!!!
// wxpay.js
// 引入express框架
const express = require('express')
// 创建express的Router实例
const router = express.Router()
// 引入dotenv库,用于加载环境变量
require("dotenv").config()
// 引入axios库,用于发送HTTP请求
const axios = require('axios')
// 导入crypto库,用于加密操作
const crypto = require('crypto')
// 导入fs库,用于读取私钥
const fs = require('fs')
// 读取私钥
const privateKey = fs.readFileSync('./apiclient_key.pem', 'utf8')
// 从环境变量中获取应用ID,商户ID,证书序列号
const { APP_ID, MCH_ID, SERIAL_NO } = process.env
// 生成请求随机串
const nonceStr = crypto.randomBytes(16).toString('hex').slice(0, 32)
// // 生成时间戳函数
const generateTimestamp = () => {
return Math.floor(Date.now() / 1000).toString();
}
// 生成签名串函数
const generateSignatureString = (...options) => {
return options.join('\n') + '\n'
}
// 微信支付接口
router.get('/wxPay', async (req, res) => {
// 可以获取前端发送过来的订单ID进行订单查询
// 然后将请求参数的信息修改即可
try {
// 请求参数
const body = {
appid: APP_ID, // 应用ID
mchid: MCH_ID, // 商户ID
description: '测试', // 商品描述
out_trade_no: '1122321322', // 商户订单号
notify_url: 'http://127.0.0.1:3000/api/wxpay/notify', // 回调地址
amount: { // 支付金额
total: 0.01 * 100,
currency: 'CNY'
},
payer: {
openid: 'oQ5V-7YibgnTkj8E2BDE6P48tDKo' // 支付者 openid
}
}
// 生成时间戳
const timeStamp = generateTimestamp()
// 生成签名串
const generateSignature = generateSignatureString('POST', '/v3/pay/transactions/jsapi', timeStamp, nonceStr, JSON.stringify(body))
// 使用私钥签名
const signature = crypto.createSign('RSA-SHA256').update(generateSignature).sign(privateKey, 'base64')
// 构造Authorization头
const authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${MCH_ID}",nonce_str="${nonceStr}",signature="${signature}",timestamp="${timeStamp}",serial_no="${SERIAL_NO}"`
console.log(authorization);
// 发起支付请求
const result = await axios.post('https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi',
body,
{
headers: {
Authorization: authorization
}
})
console.log(result.data)
// 构造订单详情扩展字符串
const package = 'prepay_id=' + result.data.prepay_id
// 构造支付签名串
const paySignStr = generateSignatureString(APP_ID, timeStamp, nonceStr, package)
// 计算支付签名
const paySignsignature = crypto.createSign('RSA-SHA256').update(paySignStr).sign(privateKey, 'base64')
// 返回支付信息
return res.status(200).send({
message: '操作成功',
data: {
appId: APP_ID, // 应用ID
timeStamp, // 时间戳
nonceStr, // 请求随机串
package, // 订单详情扩展字符串
signType: 'RSA', // 签名类型
paySign: paySignsignature // 支付签名
}
})
} catch (err) {
// 处理异常
console.log(err)
return res.status(500).send({ message: '支付失败' })
}
})
// 导出路由模块
module.exports = router
到这里就结束啦!!!