请教一个问题:1、域名备案还没有成功下来(处理回调地址URL);2、在微信支付商户平台的配置参数都是正式环境的参数,没有看到沙箱环境的参数配置界面或者提示;3、现在开发微信支付,如果用沙箱开发环境开发,但是微信支付商户平台没有沙箱的环境配置参数;4、如果用正式打款开发模式,但是域名备案没有成功。上述的问题,我是把:正式微信支付正式环境的参数输入工程,调用API,提示:支付验证签名失败。
在小程序内发起活动报名付费时,微信支付预支付请求成功(prepay_id 已获取),但调用wx.requestPayment时提示 “支付验证签名失败”。具体表现为:服务端已正确生成预支付订单及签名参数,小程序端按服务端返回参数传递给微信支付接口,但签名验证不通过,导致支付无法完成。
请协助排查以下可能导致签名验证失败的原因。
1、服务端log:
===== 发起预支付请求 =====
2025-07-15 15:42:01 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - appid: wxa8277f37d1cbd9c7
2025-07-15 15:42:01 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - mchid: 1720186147
2025-07-15 15:42:01 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - outTradeNo: 202507151542012190
2025-07-15 15:42:01 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - totalFee: 29900分
2025-07-15 15:42:01 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - openid: oxfyz7Xon6JR470i_H_R8oVVmm4o
2025-07-15 15:42:01 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 发起预支付请求:appid=wxa8277f37d1cbd9c7, mchid=1720186147, outTradeNo=202507151542012190, totalFee=29900分
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 预支付成功:prepayId=wx15154201937999a4d3b1a211fd6f3e0001
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 修正后的签名字符串(转义显示): [wxa8277f37d1cbd9c7\n1752565322\nd28f8a764be747988f7bf565cb96ba6d\nprepay_id=wx15154201937999a4d3b1a211fd6f3e0001]
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 修正后的签名字符串(原始长度): 109 字节
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService -
===== 签名核心参数(服务端生成) =====
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - appid: wxa8277f37d1cbd9c7
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - timestamp: 1752565322(类型:long)
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - nonceStr: d28f8a764be747988f7bf565cb96ba6d
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - package: prepay_id=wx15154201937999a4d3b1a211fd6f3e0001
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - signType: HMAC-SHA256
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 待签名字符串(原始): [wxa8277f37d1cbd9c7
1752565322
d28f8a764be747988f7bf565cb96ba6d
prepay_id=wx15154201937999a4d3b1a211fd6f3e0001]
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 待签名字符串(长度): 109字节
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 待签名字符串:
wxa8277f37d1cbd9c7
1752565322
d28f8a764be747988f7bf565cb96ba6d
prepay_id=wx15154201937999a4d3b1a211fd6f3e0001
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 使用的密钥类型: 商户API密钥(正确)
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 密钥完整长度: 32 字符
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 签名成功:paySign=8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 生成的paySign: 8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 签名算法: HMAC-SHA256
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 签名原始字符串: wxa8277f37d1cbd9c7
1752565322
d28f8a764be747988f7bf565cb96ba6d
prepay_id=wx15154201937999a4d3b1a211fd6f3e0001
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - API密钥: mK9p****
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - 生成签名: 8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService -
===== 返回给客户端的支付参数 =====
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - appId: wxa8277f37d1cbd9c7
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - timeStamp: 1752565322(类型:String)
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - nonceStr: d28f8a764be747988f7bf565cb96ba6d
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - package: prepay_id=wx15154201937999a4d3b1a211fd6f3e0001
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - signType: HMAC-SHA256
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - paySign: 8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO com.hy.system.pay.WxPayService - =================================
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO c.h.s.a.WechaClientController -
===== 服务端返回给客户端的支付参数 =====
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO c.h.s.a.WechaClientController - appId: wxa8277f37d1cbd9c7
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO c.h.s.a.WechaClientController - timeStamp: 1752565322
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO c.h.s.a.WechaClientController - nonceStr: d28f8a764be747988f7bf565cb96ba6d
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO c.h.s.a.WechaClientController - package: prepay_id=wx15154201937999a4d3b1a211fd6f3e0001
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO c.h.s.a.WechaClientController - signType: HMAC-SHA256
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO c.h.s.a.WechaClientController - paySign: 8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=
2025-07-15 15:42:02 [http-nio-0.0.0.0-10003-exec-6] INFO c.h.s.a.WechaClientController - =====================================
2、小程序端的log
提交数据格式: {business: "wxpay", data: {…}}
registration.js:260 [服务端返回未支付订单数据] {preview: {…}, orderInfo: {…}, paymentParams: {…}}
registration.js:311
========== 服务端返回的支付签名核心参数 ==========
registration.js:312 appId: wxa8277f37d1cbd9c7
registration.js:313 timeStamp: 1752565322 (类型: string )
registration.js:314 nonceStr: d28f8a764be747988f7bf565cb96ba6d
registration.js:315 package: prepay_id=wx15154201937999a4d3b1a211fd6f3e0001
registration.js:316 signType: HMAC-SHA256
registration.js:317 paySign: 8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=
registration.js:318 ===============================================
registration.js:354
========== 调用支付前的参数(未修改) ==========
registration.js:355 appId: wxa8277f37d1cbd9c7
registration.js:356 timeStamp: 1752565322 (类型: string )
registration.js:357 nonceStr: d28f8a764be747988f7bf565cb96ba6d
registration.js:358 package: prepay_id=wx15154201937999a4d3b1a211fd6f3e0001
registration.js:359 signType: HMAC-SHA256
registration.js:360 paySign: 8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=
registration.js:361 ===============================================
registration.js:395 [支付信息] {orderNo: "202507151542012190", priceYuan: 299, priceFen: 29900, payParams: {…}}
registration.js:398 [支付参数] {"timeStamp":"1752565322","package":"prepay_id=wx15154201937999a4d3b1a211fd6f3e0001","paySign":"8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=","appId":"wxa8277f37d1cbd9c7","signType":"HMAC-SHA256","nonceStr":"d28f8a764be747988f7bf565cb96ba6d"}
registration.js:418
========== 传给微信支付的最终签名参数 ==========
registration.js:419 timeStamp: 1752565322 (类型: string )
registration.js:420 nonceStr: d28f8a764be747988f7bf565cb96ba6d
registration.js:421 package: prepay_id=wx15154201937999a4d3b1a211fd6f3e0001
registration.js:422 signType: HMAC-SHA256
registration.js:423 paySign: 8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=
registration.js:424 ===============================================

你好,这个是v2接口规则调起的签名参数和算法规则(HMAC-SHA256)。
下面这个是v3接口规则的(算法是RSA)
你提供的签名串格式是v3的,签名算法HMAC-SHA256,是不对应的。要用对应的算法去计算签名。https://pay.weixin.qq.com/doc/v3/merchant/4012365341
1)在测试微信支付功能,我打款0.01元,小程序端提示已支付成功;
2)域名还是用开发的域名:
// 支付结果回调地址(必须是HTTPS且已备案的有效地址)
@Value("${wxpay_sandbox.notify-url}")
private String notifyUrl;
3)真实的域名(https://aitcyt.com)还在备案之中。
4) 参数配置都是真实微信支付参数
#微信支付配置参数(正式微信支付参数)
wxpay_sandbox:
appid: xxx #小程序APPID
mch-id: xxx #你的商户号
mch-serial-no: xxxx #商户证书序列号
apiKey: xxx(32位)
apiKey1: xxx
privateKey: xxx # 商户API证书私钥路径
notify-url: https://abc123.ngrok.io/api/wxpay/notify #支付结果回调地址(必须是HTTPS且已备案的有效地址)
5) 我这个支付的0.01元,为什么公司的公账没有收到了?
#支付结果回调地址(临时开发与测试的回调地址)
HMAC-SHA256算法你是怎么计算出来 “8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=” 这种格式的?
拼接待签名字符串(按微信固定规则)
// 按顺序拼接参数,用换行符\n分隔
String signatureStr = appid + "\n" + timestamp + "\n" + noncestr + "\n" + packageValue + "\n";
2、HMAC-SHA256 哈希计算(用商户密钥)
// 初始化HMAC-SHA256算法
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(merchantKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(keySpec);
// 计算哈希得到二进制字节数组
byte[] hmacBytes = mac.doFinal(signatureStr.getBytes(StandardCharsets.UTF_8));
描述:使用 32 位商户 API 密钥对字符串计算哈希,得到二进制结果
3、Base64 编码(转换为可传输字符串)
// 对二进制哈希结果进行Base64编码
String paySign = Base64.getEncoder().encodeToString(hmacBytes);
描述:将二进制字节数组转为 Base64 字符串,形成类似8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=的格式
以上三步对应日志中 “签名原始字符串→HMAC-SHA256 哈希→Base64 编码” 的完整过程,最终生成支付签名。
1. appid
含义:微信开放平台分配给小程序的唯一标识(如日志中的wxa8277f37d1cbd9c7)。
作用:标识商户的小程序身份,用于区分不同应用。
2. timestamp
含义:当前时间戳(如日志中的1752570213),类型为字符串。
作用:防止签名被重放攻击,必须与前端传递的timeStamp参数一致。
3. noncestr
含义:随机字符串(如日志中的7c32381a8cd4434ebe14d3561bb9eb59)。
作用:增加签名的随机性,避免相同参数生成相同签名。
4. packageValue
含义:预支付交易会话标识,格式为prepay_id=wx151703331714033599277e4605b4de0000。
作用:标识微信支付的预支付订单,由微信支付接口返回。
5. 末尾的\n
含义:换行符,必须严格按照四个参数 + 换行符的格式拼接(即参数1\n参数2\n参数3\n参数4\n)。
作用:微信支付规定的签名格式要求,用于确保签名计算的一致性。
关键验证点
日志中服务端计算签名的字符串为:
wxa8277f37d1cbd9c7
1752570213
7c32381a8cd4434ebe14d3561bb9eb59
prepay_id=wx151703331714033599277e4605b4de0000
private Map<String, String> generateMiniProgramParams(String prepayId) {
// 1. 生成必要参数(严格遵循微信规范)
String appid = wxPayConfig.getAppid();
long timestamp = Instant.now().getEpochSecond();
String nonceStr = java.util.UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
String packageValue = "prepay_id=" + prepayId; // 固定格式
String signType = "HMAC-SHA256"; // 签名算法(必须与计算方式一致)
// 构建待签名字符串(微信支付要求格式)
// 格式:appid\ntimestamp\nnoncestr\npackage\n(注意末尾有换行符)
// String signString = String.format("%s\n%d\n%s\n%s\n",
// appid, timestamp, nonceStr, packageValue);
// 修正后
String signString = String.format("%s\n%d\n%s\n%s", appid, timestamp, nonceStr, packageValue);
log.info("修正后的签名字符串(转义显示): [{}]", signString.replace("\n", "\\n"));
log.info("修正后的签名字符串(原始长度): {} 字节", signString.getBytes(StandardCharsets.UTF_8).length);
// 关键日志1:签名核心参数明细
log.info("\n===== 签名核心参数(服务端生成) =====");
log.info("appid: {}", appid);
log.info("timestamp: {}(类型:long)", timestamp);
log.info("nonceStr: {}", nonceStr);
log.info("package: {}", packageValue);
log.info("signType: {}", signType);
log.info("待签名字符串(原始): [{}]", signString); // 带中括号显示是否有隐藏字符
log.info("待签名字符串(长度): {}字节", signString.getBytes(StandardCharsets.UTF_8).length);
log.info("待签名字符串:\n{}", signString); // 打印原始字符串(便于调试)
Map<String, String> params = new HashMap<>();
// 3. 计算签名(核心:使用正确的API密钥)
String signature = null;
try {
// String apiKey = wxPayConfig.getApiKey(); // 获取你的APIv3密钥
String apiKey = wxPayConfig.getApiKey1(); // 获取你的APIv3密钥
// log.info("APIv3密钥(前4后4): {}****{}", apiKey.substring(0, 4), apiKey.substring(apiKey.length()-4));
// 修改点2:添加密钥验证日志
// log.info("使用的密钥类型: {}", (apiKey.startsWith("APIV3") ? "APIv3密钥(错误)" : "商户API密钥(正确)"));
// log.info("密钥完整长度: {} 字符", apiKey.length());
//新增V2
log.info("使用的密钥类型: {}", (apiKey.startsWith("APIV2") ? "APIv2密钥(错误)" : "商户API密钥(正确)"));
log.info("密钥完整长度: {} 字符", apiKey.length());
if (apiKey == null || apiKey.length() != 32) {
throw new IllegalArgumentException("无效的API密钥(必须是32位字符串)");
}
//保持签名逻辑不变
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(apiKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] hash = sha256_HMAC.doFinal(signString.getBytes(StandardCharsets.UTF_8));
signature = Base64.getEncoder().encodeToString(hash);
log.info("签名成功:paySign={}", signature);
// 关键日志2:签名结果
log.info("生成的paySign: {}", signature);
log.info("签名算法: HMAC-SHA256");
// 构建返回参数
params.put("appId", wxPayConfig.getAppid());
//时间未字符串类型
params.put("timeStamp", String.valueOf(timestamp));
params.put("nonceStr", nonceStr);
params.put("package", "prepay_id=" + prepayId);
params.put("signType", "HMAC-SHA256"); // 必须明确指定签名类型
params.put("paySign", signature);
log.info("签名原始字符串: {}", signString);
log.info("API密钥: {}", apiKey.substring(0, 4) + "****");
log.info("生成签名: {}", signature);
// 关键日志3:返回给客户端的支付参数
log.info("\n===== 返回给客户端的支付参数 =====");
log.info("appId: {}", params.get("appId"));
log.info("timeStamp: {}(类型:String)", params.get("timeStamp"));
log.info("nonceStr: {}", params.get("nonceStr"));
log.info("package: {}", params.get("package"));
log.info("signType: {}", params.get("signType"));
log.info("paySign: {}", params.get("paySign"));
log.info("=================================\n");
} catch (Exception e) {
log.error("签名计算失败", e);
throw new RuntimeException("生成支付签名失败", e);
}
return params;
}
1、HMAC-SHA256 计算出该格式的核心是 “哈希计算 + Base64 编码”,关键代码片段及描述如下:
拼接待签名字符串(按微信固定规则)
// 按顺序拼接参数,用换行符\n分隔
String signatureStr = appid + "\n" + timestamp + "\n" + noncestr + "\n" + packageValue + "\n";
2、HMAC-SHA256 哈希计算(用商户密钥)
// 初始化HMAC-SHA256算法
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(merchantKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(keySpec);
// 计算哈希得到二进制字节数组
byte[] hmacBytes = mac.doFinal(signatureStr.getBytes(StandardCharsets.UTF_8));
描述:使用 32 位商户 API 密钥对字符串计算哈希,得到二进制结果
3、Base64 编码(转换为可传输字符串)
// 对二进制哈希结果进行Base64编码
String paySign = Base64.getEncoder().encodeToString(hmacBytes);
描述:将二进制字节数组转为 Base64 字符串,形成类似8Qqyv9p9cFp7h4uEdS0ahYK+Hv/JjynOJs3Mwxyzki4=的格式
以上三步对应日志中 “签名原始字符串→HMAC-SHA256 哈希→Base64 编码” 的完整过程,最终生成支付签名。
1. appid
含义:微信开放平台分配给小程序的唯一标识(如日志中的wxa8277f37d1cbd9c7)。
作用:标识商户的小程序身份,用于区分不同应用。
2. timestamp
含义:当前时间戳(如日志中的1752570213),类型为字符串。
作用:防止签名被重放攻击,必须与前端传递的timeStamp参数一致。
3. noncestr
含义:随机字符串(如日志中的7c32381a8cd4434ebe14d3561bb9eb59)。
作用:增加签名的随机性,避免相同参数生成相同签名。
4. packageValue
含义:预支付交易会话标识,格式为prepay_id=wx151703331714033599277e4605b4de0000。
作用:标识微信支付的预支付订单,由微信支付接口返回。
5. 末尾的\n
含义:换行符,必须严格按照四个参数 + 换行符的格式拼接(即参数1\n参数2\n参数3\n参数4\n)。
作用:微信支付规定的签名格式要求,用于确保签名计算的一致性。
关键验证点
日志中服务端计算签名的字符串为:
wxa8277f37d1cbd9c7
1752570213
7c32381a8cd4434ebe14d3561bb9eb59
prepay_id=wx151703331714033599277e4605b4de0000