微信小程序对接微信支付所遇问题合集

写在前面: 

1. 后端使用微信官方sdk会简单很多,在第五点有我写的java代码示例。

2. 以下所有问题均基于uniapp开发微信小程序。

3. 所使用的工具版本为:

        1、微信开发者工具:稳定版 Stable Build (1.06.2402040);

        2、uniapp工具:HBuilder X 3.99;

        3、后端程序语言:java;

 4. 相关文档汇总:

        1、WxJava - MiniApp Java SDK 4.6.0 API

        2、wechatpay-java/README.md at main · wechatpay-apiv3/wechatpay-java · GitHub

        3、网络 | 微信开放文档

        4、开发指引 - JSAPI支付 | 微信支付商户文档中心

5. 官方支付流程:

一、请求路径不在以下 request 合法域名列表中

        1. 报错详细信息:

                    http://localhost:30013 不在以下 request 合法域名列表中,请参考文档:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html

        2. 解决思路:

                2.1 将域名配置在小程序中

                          根据报错信息查看微信相关文档,网络 | 微信开放文档

                2.2 如果只是临时修改或有其他需求可以修改微信开发工具中的配置

                          启用设置中的“不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书”选项

二、获取用户openid出现40029响应码

        1. 请求url:

                https://api.weixin.qq.com/sns/jscode2session

        2. 微信响应原文:

                 Response Body: {"errcode":40029,"errmsg":"invalid code, rid: 660a3033-68f26499-0b8d2eb4"}

        3. 解决思路:

                3.1 查看代码code是否被使用了两次;

                3.2 检查小程序配置的appid是否与代码中一致、appSecret是否正确

                         检查小程序配置的appid:看appid是否与微信开发工具中配置的一致。

三、uni.requestPayment()下单时产生参数校验错误parameter error

        1. 报错具体信息:

                requestPayment:fail parameter error: parameter.timeStamp should be String instead of Undefined;parameter.nonceStr should be String instead of Undefined;parameter.package should be String instead of Undefined;parameter.signType should be String instead of Undefined;parameter.paySign should be String instead of Undefined;

        2. 解决思路:

                可以将所有参数都打印出来查看。下面出现错误可能原因:

                2.1 请求数据字段数据类型必须为String

                        后台可能返回的不是String而是int类型,需要调整为String;

                2.2 响应数据取用层级不对。

                        比如后台返回的数据是{data:{data:{}}},只取到数据所在层级前几层;

                2.3 请求数据所放层级不对。

                        正确的应该是paySign等参数与success平行,结果参照了其他请求示例,将这些参数放在orderInfo下面了,正确的官方请求示例为:

 四、解密退款通知时产生Tag mismatch错误

        官方文档相关问题链接:微信支付-QA文档

        1. 报错具体信息:

                javax.crypto.AEADBadTagException: Tag mismatch!

        2. 相关代码:

//原始代码
JSONObject resource = jsonObject.getJSONObject("resource");
AesUtil aesUtil = new AesUtil("v3密钥".getBytes());
String s = aesUtil.decryptToString(
        resource.getString("associated_data").getBytes(),
        resource.getString("nonce").getBytes(),
        resource.getString("ciphertext")
);

        3. 解决思路:

                在网上查询后发现的可能原因:

                3.1 v3秘钥有问题。

                        检查使用的v3秘钥是否有问题

                3.2 解密入参需要以utf-8转换。

                        相关文章链接:分享微信支付回调解密提示:Tag mismatch | 微信开放社区

//更改后
JSONObject resource = jsonObject.getJSONObject("resource");
AesUtil aesUtil = new AesUtil("你的密钥".getBytes(StandardCharsets.UTF_8));
String s = aesUtil.decryptToString(
        resource.getString("associated_data").getBytes(StandardCharsets.UTF_8),
        resource.getString("nonce").getBytes(StandardCharsets.UTF_8),
        resource.getString("ciphertext")
);

                3.3 解密时接口遗漏传入附加数据(associated_data)。

                        我忘了我为了美观规范写成了小驼峰的形式,导致 接收数据类的字段名 和 微信传过来的 不一致,所以associated_data没有接收到 (最好使用微信官方sdk,各种实体类和方法就不用再次创建了)

//微信原始发送的json
{"id":"xxx","create_time":"2024-04-02T11:53:30+08:00","resource_type":"encrypt-{
    "id": "xxx",
    "create_time": "2024-04-02T11:53:30+08:00",
    "resource_type": "encrypt-resource",
    "event_type": "REFUND.SUCCESS",
    "summary": "退款成功",
    "resource": {
        "original_type": "refund",
        "algorithm": "AEAD_AES_256_GCM",
        "ciphertext": "xxx",
        "associated_data": "refund",
        "nonce": "xxx"
    }
}

//错误接收的json
{
    "id": "xxx",
    "resource": {
        "algorithm": "AEAD_AES_256_GCM",
        "ciphertext": "xxx",
        "nonce": "xxx"
    },
    "summary": "退款成功"
}

五、代码示例:

        后端使用微信官方sdk示例。

        1. pom:

<!--  微信sdk依赖   -->
<dependency>
    <groupId>com.github.wechatpay-apiv3</groupId>
    <artifactId>wechatpay-java</artifactId>
    <version>0.2.12</version>
</dependency>

        2. 具体代码: 

/**
* refundApply 退款申请
*
* @param request
* @return Result<java.lang.Object>
*/
@PostMapping("refund-apply")
public Result<Object> refundApply(@RequestBody CreateRequest request) {
        // 获取.p12文件并获取其中的信息
        P12InfoVo vo = getP12Info(); 
        // 初始化商户配置
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(readWechatProfile.getMchId())
                        .privateKey(vo.getPrivateKey())
                        .merchantSerialNumber(vo.getSerialNo())
                        .apiV3Key(readWechatProfile.getV3())
                        .build();

        // 初始化服务,使用微信sdk对应功能的service
        refundService = new RefundService.Builder().config(config).build();
        // 调用对应service中的接口
        Refund response = refundService.create(request);
        log.info("退款申请响应:{}", response);
        return Result.success();
}     

        其中privateKey方法是可以替换成读取私钥的.pem文件地址,具体可查看类中api。另外读取p12文件api:

public P12InfoVo getP12Info2() {
        String p12Path = "xx/xx/xxx.p12";// p12证书路径
        char[] mchid = "xxx" .toCharArray();//商户号
        try {
            // 获取文件流
            FileInputStream fileInputStream = new FileInputStream(p12Path);

            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(fileInputStream, mchid);
            String keyAlias = null;
            //解析证书,必须有别名
            Enumeration<String> aliases = keyStore.aliases();
            if (aliases.hasMoreElements()) {
                keyAlias = aliases.nextElement();
            }
            //解析私钥
            PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, mchid);
            Certificate cert = keyStore.getCertificate(keyAlias);
            BigInteger serialNumber = ((X509CertImpl) cert).getSerialNumber();
            //证书一般都使用16进制表示
            String certSn = serialNumber.toString(16).toUpperCase();
            //设置证书公钥、私钥、序列号
            return P12InfoVo.builder()
                    .publicKey(cert.getPublicKey())
                    .privateKey(privateKey)
                    .serialNo(certSn)
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
}

  • 19
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值