收藏
回答

接不上虚拟支付非逼我接虚拟支付的问题?

问题描述

调用虚拟支付接口 wx.requestVirtualPayment 返回错误:

{errMsg: "requestVirtualPayment:fail PAY_SIG_INVALID", errno: -15006, errCode: -15006}

尽管云函数生成的签名(paySig)经本地工具验证正确,且前端参数传递无误。


基本信息

  • 小程序 AppID:wx55d13d49328e0f4a
  • OfferID:1450493928
  • 道具ID:unit_1(1元道具,已发布线上版本)
  • 支付环境:正式环境(env=0

已进行的排查

  1. 道具发布状态:unit_1 已在虚拟支付后台发布为“线上版本”。
  2. 云函数签名生成:
  • 使用正式的 AppKey 。
  • 严格按照微信文档进行字段排序、类型转换。
  • 打印的 signDataStr 和 paySig 如下(示例):
  • text
signDataStr: {"attach":"test","buyQuantity":1,"currencyType":"CNY","env":0,"goodsPrice":100,"offerId":"1450493928","outTradeNo":"B41658151581","productId":"unit_1","zoneId":"1"}
paySig: fb84c62b1f331fc0d1c03859b05d05930a19915cc3686ea0e6353bb8391677ee
  • 使用相同字符串和 AppKey 在本地 HMAC-SHA256 工具计算,结果与云函数一致。
  1. 前端调用:
  • mode 明确为 'short_series_goods'
  • signDatapaySigsignature 直接使用云函数返回的字符串,未做额外处理。
  • 控制台打印的 virtualPayParams 与云函数返回一致。

附件材料

  • 云函数完整日志(包含签名生成和返回结果)
  • 前端控制台输出(包含 orderRes 和 virtualPayParams 内容)
  • 道具 unit_1 后台截图(显示“线上版本”)

请求帮助

希望微信后台协助查询该次签名校验失败的具体原因,可能是:

  • zoneId 字段类型要求(字符串 vs 数字)在正式环境有特殊校验。
  • 订单号 outTradeNo 是否因之前测试被标记为异常。
  • 正式环境 AppKey 与后台记录是否完全一致(尽管已核对)。
  • 其他未知的签名校验细节。

如有需要,可提供测试用的 outTradeNo 供后台跟踪。


联系方式

18810969734

请将以上信息连同附件一并提交,以便快速解决。


回答关注问题邀请回答
收藏

4 个回答

  • 神经蛙
    神经蛙
    03-24

    调用云函数传递的参数代码发出来看看

    03-24
    有用 1
    回复 6
    • Sniper
      Sniper
      03-24
      云函数中生成签名的核心代码


      function generateVirtualPayParams(offerId, appKey, sessionKey, outTradeNo, productId, goodsPrice, buyQuantity, attach, env = 0) {
        const signDataObj = {
          attach: typeof attach === 'string' ? attach : JSON.stringify(attach),
          buyQuantity: Number(buyQuantity),
          currencyType: 'CNY',
          env: Number(env),
          goodsPrice: Number(goodsPrice),
          offerId: String(offerId),
          outTradeNo: String(outTradeNo),
          productId: String(productId),
          zoneId: '1' // 也尝试过数字1,问题依旧
        };
        const sortedKeys = Object.keys(signDataObj).sort();
        const sortedSignData = {};
        sortedKeys.forEach(key => { sortedSignData[key] = signDataObj[key]; });
        const signDataStr = JSON.stringify(sortedSignData);
        const paySig = crypto.createHmac('sha256', appKey).update(signDataStr).digest('hex');
        const signature = crypto.createHmac('sha256', sessionKey).update(signDataStr).digest('hex');
        return { signData: signDataStr, paySig, signature };
      }
      前端调用虚拟支付的代码(直接使用云函数返回的参数):
      javascript
      wx.requestVirtualPayment({
        mode: 'short_series_goods',
        signData: signData, // 云函数返回的字符串
        paySig: paySig,
        signature: signature,
        success: ...,
        fail: ...
      });
      03-24
      回复
    • 神经蛙
      神经蛙
      03-24回复Sniper
      算法搞错了, 需要 requestVirtualPayment + '&'+signDataStr
      03-24
      回复
    • Sniper
      Sniper
      03-24回复神经蛙
      感谢您的指正。我们这里使用的是小程序端 wx.requestVirtualPayment 接口,根据官方文档《虚拟支付 - 签名生成》,其 paySig 生成规则为:
      text
      paySig = to_hex(hmac_sha256(appKey, signData))
      其中 signData 是包含支付相关字段的 JSON 字符串(已排序),不包含 uri 部分。我们已严格按照此规则实现,且本地验证签名与云函数生成一致。
      03-24
      回复
    • 神经蛙
      神经蛙
      03-24回复Sniper
      需要的,要不你试试
      03-24
      回复
    • Sniper
      Sniper
      03-24回复神经蛙
      感谢 我尝试一下
      03-24
      回复
    查看更多(1)
  • Memory (私信不回复)
    Memory (私信不回复)
    03-24

    key 和环境 用对了么?

    03-24
    有用
    回复 3
    • Sniper
      Sniper
      03-24
      环境与Key确认:
      正式环境 env = 0 沙盒环境也试过 一样的问题
      使用的 AppKey 是从虚拟支付后台复制的现网 
      道具 unit_1 已发布为“线上版本”,
      03-24
      回复
    • Memory (私信不回复)
      Memory (私信不回复)
      03-24回复Sniper
      贴代码
      03-24
      回复
    • Sniper
      Sniper
      03-24
      感谢老哥 上面的人帮我解决了!
      03-24
      回复
  • Sniper
    Sniper
    03-24

    能不能有个真人回复啊 这AI回的没用啊

    03-24
    有用
    回复
  • 智能回答 智能回答 本次回答由AI生成
    03-24
    有用
登录 后发表内容