uniapp小程序如何使用微信支付


前言

这里介绍微信小程序如何使用微信进行支付。并且提供前端代码以及后端代码(nodeJs)。这里后端使用nodeJs写的哈。
需要准备:
1、小程序(企业级或个体工商)的appId
2、微信支付商户的商户号,以及v2支付密钥


一、前端登录将code发送后端

提示:以下内容流程:前端进行uni.login登录,将code传给后端,后端根据code获取用户的openid
因为没有使用数据库,也没有使用Redis去缓存openid。所以这里拿到openid后,写死在config.js配置文件中

1、前端代码
<script setup>
	const handleLogin = async () => {
		const loginRes = await uni.login({provider: 'weixin'}); // 获取微信登录code
		// 发送code到服务器   后端通过code获取到用户openid
		const res = await uni.request({
			url: 'http://127.0.0.1:3030/api/login',
			method: 'POST',
			data: {code: loginRes.code}
		});
		// 存储返回的 token
		if (res.data.code === 200) {
		  uni.setStorageSync('token', res.data.token)
		  uni.showToast({
			title: '登录成功',
			success() {
				uni.switchTab({url:'/pages/home/home'})
			}
		  });
		  
		}
	};
</script>
2、nodeJs代码

代码示例中提到的config.js代码文件 后面会贴出来

// src/services/login.js
const axios = require('axios');
const config = require('../../config/config'); // 将配置独立出来
// 获取openid session_key
async function getOpenid(code) {
  const weixinRes = await axios.get('https://api.weixin.qq.com/sns/jscode2session', {
    params: {
      appid: config.appId,
      secret: config.appSecret,
      js_code: code,
      grant_type: 'authorization_code'
    }
  })
  return weixinRes;
}
// 用 code 换取 session_key 和 openid...
module.exports = { getOpenid };

// app.js
app.post('/api/login', async (req, res) => {
    try {
      const { code } = req.body
      // 1. 用 code 换取 session_key 和 openid
      const weixinRes = await getOpenid(code);
      // 2. 生成自定义 token(使用 JWT)
      const token = jwt.sign(
        { openid: weixinRes.data.openid },
        'your-secret-key',
        { expiresIn: '7d' }
      )
      // 3. 登录成功 返回 token 给客户端
      res.json({
        code: 200,
        token: token,
        openid: weixinRes.data.openid
      });
    } catch (error) {
      res.status(500).json({ code: 500, message: '登录失败' })
    }
})

二、前端调用接口创建预支付订单

前端调用接口创建预支付订单,后端根据传递的商品信息和小程序appid,商户号,用户openid等参数,去调用微信提供的统一下单接口,最后返回uni.requestPayment所需要的参数

前端代码
<script setup>
	import {ref, reactive} from 'vue';
	// 商品信息
	const productsInfo = reactive([{
		title: 'xxx商品',
		money: '0.01',
		quantity: 1,
	}]);
	
	// 创建预支付订单
	const handleCreateOrder = async (data) => {
		const res = await uni.request({
			url: 'http://127.0.0.1:3030/api/createOrder',
			method: 'POST',
			data: {...data}
		});
		if (res.data.code === 200) {
		  uni.showToast({title: '下单成功'});
		  // 创建订单成功后,唤起微信支付
		  const payParams = res.data.data;
		  uni.getProvider({ // 服务提供商
		  	service: 'payment',
			success(res) {
				const provider = res.provider;
				// 唤起微信支付
				uni.requestPayment({
					provider,
					orderInfo: {...data},
					timeStamp: payParams.timeStamp,
					nonceStr: payParams.nonceStr,
					package: payParams.package,
					signType: payParams.signType,
					paySign: payParams.paySign,
				})
			}
		  })
		};
	}
</script>
nodeJs代码
// src/services/wechat-pay.js
const crypto = require('crypto');
const axios = require('axios');
const { parseStringPromise } = require('xml2js'); // XML解析库
const config = require('../../config/config'); // 配置独立出来

// 生成签名
function createSign(params) {
  const stringA = Object.keys(params)
    .filter(key => params[key] !== '' && key !== 'sign') // 过滤空值和sign字段
    .sort() // 按ASCII码升序排序
    .map(key => `${key}=${params[key]}`)
    .join('&');
  
  const stringSignTemp = stringA + `&key=${config.apiKey}`;
  const sign = crypto.createHash('md5').update(stringSignTemp).digest('hex').toUpperCase();
  return sign;
}
// XML 解析
async function parseXml(xml) {
    try {
      const result = await parseStringPromise(xml);
      const formatted = {};
      for (const [key, value] of Object.entries(result.xml)) {
        formatted[key] = value[0];
      }
      return formatted;
    } catch (error) {
      throw new Error('XML 解析失败');
    }
}

// 统一下单接口
async function createOrder(orderData) {
  const params = {
    appid: config.appId, // 小程序appid
    mch_id: config.mchId, // 商户号
    nonce_str: Math.random().toString(36).substr(2, 15), // 随机字符串(确保无重复)
    body: orderData.title, // 商品描述
    out_trade_no: `ORDER_${Date.now()}`, // 商户订单号
    total_fee: orderData.totalFee, // 商品金额(单位分)
    spbill_create_ip: '192.0.0.1', // 用户端实际IP
    notify_url: config.notifyUrl, // 回调地址
    trade_type: 'JSAPI', // 交易类型
    openid: config.openId, // 支付用户openid
  };
  params.sign = createSign(params);
  // 调用微信提供的统一下单接口
  const response = await axios.post(
    'https://api.mch.weixin.qq.com/pay/unifiedorder',
    `<xml>${Object.entries(params).map(([key, value]) => `<${key}>${key != 'sign'?'<![CDATA[':''}${value}${key != 'sign'?']]>':''}</${key}>`).join('')}</xml>`,
    { headers: { 'Content-Type': 'application/xml' } }
  );
  // 解析返回的XML数据
  const result = await parseXml(response.data);
  return result;
}

// 微信支付功能封装...
module.exports = { createOrder, createSign};
// config.js
const APIKEY = 'xxxxx';
const APPID = 'xxxxx';
const MCHID = 'xxxx';
const NOTIFY_URL = 'https://127.0.0.1:3030/api/payCallback';
const APPSECRET = 'xxxxx';
const OPENID = 'xxxx';

module.exports = {
    appId: APPID, // 小程序appId
    appSecret: APPSECRET, // 小程序密钥
    mchId: MCHID, // 商户号
    apiKey: APIKEY, // 支付密钥
    notifyUrl: NOTIFY_URL, // 支付回调
    openId: OPENID, // 用户openid
}

总结

// 调用微信提供的统一下单接口
  const response = await axios.post(
    'https://api.mch.weixin.qq.com/pay/unifiedorder',
    `<xml>${Object.entries(params).map(([key, value]) => `<${key}>${key != 'sign'?'<![CDATA[':''}${value}${key != 'sign'?']]>':''}</${key}>`).join('')}</xml>`,
    { headers: { 'Content-Type': 'application/xml' } }
  );
注意:这里sign签名除外,其他参数必须要使用'<![CDATA[ ]]>'包裹。例如:`<![CDATA[${value}]]>`

nodeJs后端用到依赖:

"axios": "^1.7.9",
"body-parser": "^1.20.3",
"dotenv": "^16.4.7",
"express": "^4.21.2",
"jsonwebtoken": "^9.0.2",
"xml2js": "^0.6.2"
"nodemon": "^3.1.9"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

F2E_zeke

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值