微信虚拟支付错误码:1000到10056,一路踩坑到支付成功

📅 2026/7/1 17:01:12
微信虚拟支付错误码:1000到10056,一路踩坑到支付成功
一、前期准备按照官网先进行配置虚拟支付 | 微信开放文档拿到相关参数appid、appSecret、offerId、appKey现网、sandboxAppKey沙网、env0:正式环境、1沙网环境获取如下图二、报错信息{errMsg: requestVirtualPayment:fail PAY_SIG_INVALID, errno: -15006, errCode: -15006} {errno: 1001, errMsg: requestVirtualPayment:fail parameter error: parame…meter.mode should be String instead of Undefined;} {errno: 1001, errMsg: requestVirtualPayment:fail parameter error: parameter.mode should be String instead of Undefined;} {errno:1001,errMsg:requestVirtualPayment:fail parameter error: parameter.signData should be String instead of Object;parameter.mode should be String instead of Undefined;} ....三、完整代码wx.requestVirtualPayment({ env: 0, // 线上正式环境消除开发者扫码调试弹窗 signData: payInfo.signDataStr, paySig: payInfo.paySig, signature: payInfo.signature, mode: short_series_goods, success: () { // 仅弹窗打开不代表支付完成不执行轮询 }, fail: (err) { console.error(支付弹窗关闭(取消/付款完成), err); // 弹窗关闭立刻查询订单状态 this.pollOrderStatus(this.currentOrderNo); } });public MapString, Object createOrder(PayOrderVo payOrderVo) throws Exception { logger.info( 开始创建VIP会员虚拟支付订单 ); //自己的业务处理-创建订单信息 // 5. 构造米大师标准signData TreeMapVIP道具专用 short_series_goods MapString, Object signDataMap new TreeMap(); signDataMap.put(offerId, offerId); signDataMap.put(env, env); signDataMap.put(mode, short_series_goods); // 单次付费道具/会员固定值 signDataMap.put(currencyType, CNY); signDataMap.put(buyQuantity, 1); // 单次购买1份会员 signDataMap.put(productId, String.valueOf(goods.getId())); // 价格转分为数字类型解决-15016字段类型报错 int priceCent goods.getPrice().multiply(new BigDecimal(100)).intValue(); signDataMap.put(goodsPrice, priceCent); signDataMap.put(outTradeNo, orderNo); signDataMap.put(attach, ); // FastJSON稳定序列化避免格式差异导致签名失效 String signDataStr JSON.toJSONString(signDataMap, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.DisableCircularReferenceDetect ); logger.info(标准signDataStr{}, signDataStr); // 6. 区分环境选取对应AppKey String selectedAppKey env 1 ? sandboxAppKey : appKey; logger.info(当前环境env{}, 使用密钥AppKey{}, env, selectedAppKey); // 7. 生成paySig修复核心删除小游戏前缀仅原始signDataStr签名 String paySig generatePaySig(signDataStr, selectedAppKey); logger.info(生成paySig{}, paySig); // 8. 生成用户侧signaturesessionKey签名无修改 String signature generateSignature(signDataStr, sessionKey); logger.info(生成signature{}, signature); // 9. 返回前端支付参数 MapString, Object result new LinkedHashMap(); result.put(orderNo, orderNo); result.put(offerId, offerId); result.put(goodsPrice, priceCent); result.put(paySig, paySig); result.put(signature, signature); result.put(signData, signDataMap); result.put(signDataStr, signDataStr); result.put(attach, ); return result; } /** * 小程序VIP道具付费 paySig 签名无小游戏前缀适配short_series_goods */ private String generatePaySig(String signDataStr, String appKey) throws Exception { // 必须拼接固定前缀 requestVirtualPayment String signSource requestVirtualPayment signDataStr; return hmacSha256Hex(signSource, appKey); } /** * 用户sessionKey签名用于前端校验 */ private String generateSignature(String signDataStr, String sessionKey) throws Exception { return hmacSha256Hex(signDataStr, sessionKey); } /** * 标准HMAC-SHA256 输出全小写16进制米大师统一标准 */ private String hmacSha256Hex(String data, String secret) throws Exception { Mac mac Mac.getInstance(HmacSHA256); SecretKeySpec keySpec new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), HmacSHA256); mac.init(keySpec); byte[] hashBytes mac.doFinal(data.getBytes(StandardCharsets.UTF_8)); StringBuilder hexSb new StringBuilder(); for (byte b : hashBytes) { hexSb.append(String.format(%02x, b)); } return hexSb.toString(); }注意mode参数值我是VIP充值固定值为short_series_goodspaySid签名算法必须拼接“requestVirtualPayment”