微信小程序支付 参数异常 及 验证签名失败 总结

微信小程序支付流程

如下图所示,微信支付官方给出了小程序支付的流程

在这里插入图片描述
**

微信图示开发使用步骤

用户进入小程序,选择商品服务,确认下单;
小程序前台将用户的请求以及用户信息(openid),提交到小程序后台;
小程序后台生成预订单,调用微信支付的统一下单接口,将小程序的预订单提交到微信支付;
通过返回的return_code字段,判断提交成功后,获取微信支付返回的成功信息即预付单信息,包括prepay_id
将微信返回的预付单信息,加上其他必要信息,签名后,返回给前端用于拉起微信收银台,完成支付。
根据小程序后台提交预订单到微信后台时所提交的通知地址,或小程序主动调用微信支付接口,可查询支付结果。

小程序后台调用微信支付预订单接口

前提参数:

	//小程序appid
	private String appid;

	//小程序关联的商户号
	private String partner;

	//商户号的秘钥
	private String partnerkey;在这里插入代码片
  1. 参数封装,小程序调用微信预订单借口至少需要封装以下,其他参考微信支付
		//1.参数封装
		Map param=new HashMap();
		//公众账号ID
		param.put("appid", appid);
		//商户号
		param.put("mch_id", partner);
		//随机字符串
		param.put("nonce_str", WXPayUtil.generateNonceStr());
		param.put("body", "芬达");
		//交易订单号
		param.put("out_trade_no", outTradeNo);
		//金额(分)
		param.put("total_fee", totalFee);
		param.put("spbill_create_ip", "127.0.0.1");
		param.put("notify_url", "https://www.baidu.com");
		//交易类型
		param.put("trade_type", "JSAPI");
		//用户标示
		param.put("openid", openid);

至关重要的签名,在封装参数的最后一步进行,根据微信官方提供的工具类WXPayUtil可以实现;

String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey);
System.out.println("请求的参数:"+xmlParam);

调用微信接口,需要传xml格式的参数,可以使用**WXPayUtil.generateSignedXml(param, partnerkey)**方法将HashMap类型的参数转换为xml类型,顺便将传入的参数按,秘钥加密封装进一个签名,调用该方法得出的参数就是带有签名的xml类型参数了。

直接调用该方法获得请求数据后,调用接口获得结果,这里我用的是一个HttpClient工具类,方便发送https请求,网上随处可以找到。

			//2.发送请求
			HttpClient httpClient=new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
			httpClient.setHttps(true);
			httpClient.setXmlParam(xmlParam);
			httpClient.post();
			//3.获取结果
			String xmlResult = httpClient.getContent();
			Map<String, String> mapResult = WXPayUtil.xmlToMap(xmlResult);
			System.out.println("微信返回结果"+mapResult);

  • 微信返回的结果,包括微信的签名,调起支付的prepay_id等数据

返回前台数据用于调起微信支付收银台

  1. 调用wx.requestPayment(OBJECT)发起微信支付
  2. Object参数说明

在这里插入图片描述PS:字段名最好到官方API 复制以免出错

  1. 必要的五个参数,除了随机字符串,和签名外其他都可自行获得。随机字符串推荐用微信工具类**WXPayUtil.generateNonceStr()**获得随机字符串。

  2. 签名的获得: · 签名的获得可以根据官方签名规则,自己去手动加密获得签名。 . 根据WXPayUtil工具类去加密WXPayUtil.generateSignature(repData,partnerkey),此方法就是对Map类型的参数repData,用partnerKey进行签名,并返回签名。

  3. 获得签名的注意事项
    通过工具类获得签名时,有且只需五个参数,且要注意:

    1. 跟提交到微信支付预订单时的参数不一样,这里需要注意区分大小写,此处均为驼峰写法,一定注意是appId,I是大写,其他参数也是一样。
    2. 一定要添上签名类型signType,看源码发现官方工具类默认就是按照MD5加密的,所以我一直以为不需要添加签名方式,因为调用接口时数据签名也未添加签名方式,此处一定区分开,否则把数据发送给前端调用会发生验证签名失败。
    3. 代码如下:
//返回前端数据
		if (mapResult.get("return_code").equals("SUCCESS")){
			//返回给APP端的参数,APP端再调起支付接口
			Map<String,String> repData = new HashMap<>();
			//注意参数要区分大小写
			repData.put("appId",appid);
			//repData.put("prepayid",mapResult.get("prepay_id"));
			String packag="prepay_id="+mapResult.get("prepay_id");
			repData.put("package",packag);
			//要添加签名方式
			repData.put("signType","MD5");
			repData.put("nonceStr",WXPayUtil.generateNonceStr());
			repData.put("timeStamp",String.valueOf(System.currentTimeMillis()/1000));
			//签名
			String sign = WXPayUtil.generateSignature(repData,partnerkey);
			repData.put("prepayid",mapResult.get("prepay_id"));
			repData.put("mch_id",partner);
			repData.put("sign",sign);
			repData.put("timestamp",repData.get("timeStamp"));
			return repData;

  1. 前端根据返回的数据,一一对应调用方法就能调起微信支付收银台了

BUG总结

  1. 调用微信预订单接口失败
    1. 商户号未与小程序绑定
    2. 通知地址不是https类型
    3. 交易类型没指定为JSAPI
    4. 订单号重复
  2. 可以正常调用微信预订单接口,能获得微信支付返回的prepay_id,但是小程序调起收银台失败
    1. 参数错误,会返回调用支付jsapi缺少参数:total_fee,此时与签名没关系,需要检查方法参数,随机字符串和package对应的参数值,还有就是,下预订单使用的用户openid和拉起支付的用户,必须是同一个,不然会报错,我就是遇到这个错误。
    2. 支付验证签名失败,这个与获得签名有关系,返回的签名不正确
      自己手动获取签名,要注意参数的顺序以及大小写
      使用微信工具类获得签名时,也要注意大小写,并且在要签名的参数中加上签名方式repData.put(“signType”,“MD5”);。

总结

  1. 最后我把WXPayUtil工具类的maven地址贴出来
<dependency>
	<groupId>com.github.wxpay</groupId>
	<artifactId>wxpay-sdk</artifactId>
	<version>0.0.3</version>
</dependency>

  1. 将整个后端发起预订单的代码贴出来,仅供参考,根据业务不同在变化
/**
	 *
	创建预订单信息,发起支付
	 */
	@Override
	public Map createNative(String outTradeNo, String totalFee ,String openid) {
		//1.参数封装
		Map param=new HashMap();
		//公众账号ID
		param.put("appid", appid);
		//商户号
		param.put("mch_id", partner);
		//随机字符串
		param.put("nonce_str", WXPayUtil.generateNonceStr());
		param.put("body", "芬达");
		//交易订单号
		param.put("out_trade_no", outTradeNo);
		//金额(分)
		param.put("total_fee", totalFee);
		param.put("spbill_create_ip", "127.0.0.1");
		param.put("notify_url", "https://www.baidu.com");
		//交易类型
		param.put("trade_type", "JSAPI");
		//用户标示
		param.put("openid", openid);

		try {
			String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey);
			System.out.println("请求的参数:"+xmlParam);

			//2.发送请求
			HttpClient httpClient=new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
			httpClient.setHttps(true);
			httpClient.setXmlParam(xmlParam);
			httpClient.post();

			//3.获取结果
			String xmlResult = httpClient.getContent();
			Map<String, String> mapResult = WXPayUtil.xmlToMap(xmlResult);
			System.out.println("微信返回结果"+mapResult);
			//返回前端数据
			if (mapResult.get("return_code").equals("SUCCESS")){
				//返回给APP端的参数,APP端再调起支付接口
				Map<String,String> repData = new HashMap<>();
				repData.put("appId",appid);
			
				String packag="prepay_id="+mapResult.get("prepay_id");
				
				repData.put("package",packag);
				repData.put("signType","MD5");
				repData.put("nonceStr",WXPayUtil.generateNonceStr());
				repData.put("timeStamp",String.valueOf(System.currentTimeMillis()/1000));

				//签名
				String sign = WXPayUtil.generateSignature(repData,partnerkey);
				repData.put("prepayid",mapResult.get("prepay_id"));
				repData.put("mch_id",partner);
				repData.put("sign",sign);
				repData.put("timestamp",repData.get("timeStamp"));

				return repData;
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return new HashMap();
	}

前端示例代码

wx.requestPayment(
{
'timeStamp': '',
'nonceStr': '',
'package': '',
'signType': 'MD5',
'paySign': '',
'success':function(res){},
'fail':function(res){},
'complete':function(res){}
})

  1. 关于订单查询、关闭大同小异,只需要换一个接口地址和参数就可以实现,在这里不做过多的说明
  2. 关于小程序退款,我会在下个文章里介绍分享,希望关注一波。

**

文章摘自:https://blog.csdn.net/qq_38371367/article/details/87195489

感谢大佬分享 如有侵权联系删除

**

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值