收藏
回答

虚拟支付服务端请求 /xpay/query_order接口报支付签名(pay_sig)校验失败?

调用微信虚拟支付 `query_order` 接口时,始终返回**支付签名(pay_sig)校验失败**(错误rid: 69aa8f50-74f4c3df-45f16563),已核对AppKey(沙箱/正式环境匹配)、uri、参数值均无误,请求帮忙排查签名生成逻辑问题。


### 关键代码片段
```java
// 1. 构建有序请求体(确保字段顺序固定)
TreeMap requestMap = new TreeMap<>();
requestMap.put("openid", openid); // 从订单中获取的真实openid
requestMap.put("env", env); // 前端传入的env(0=正式/1=沙箱)
requestMap.put("order_id", payOrder.getOutTradeNo()); // 订单号


// 2. 生成无格式化JSON字符串(禁用空格/换行)
String postData = JSONObject.toJSONString(requestMap, SerializerFeature.DisableCircularReferenceDetect);


// 3. 生成pay_sig签名(严格按官方算法)
String uri = "/xpay/query_order";
String paySig = VirtualPayApiUtil.generatePaySig(uri, postData, appKey);


// 4. 签名生成工具方法
public static String generatePaySig(String uri, String postBody, String appKey) {
    String needSignMsg = uri + '&' + postBody;
    // 使用commons-codec的HmacUtils,算法为HMAC-SHA256
    return HmacUtils.hmacSha256Hex(appKey, needSignMsg);
}


// 5. 接口调用(Feign)
String resStr = virtualPayFeignClient.queryOrder(token.getAccessToken(), paySig, requestMap);


```**
 * 查询订单接口
 * query_order
 *
 * @param accessToken 访问令牌
 * @param paySig 支付签名
 * @param requestBody 请求体
 * @return 订单信息
 */
@RequestMapping(
        value = "/xpay/query_order",
        method = RequestMethod.POST,
        consumes = MediaType.APPLICATION_JSON_VALUE, // 显式指定JSON格式
        produces = MediaType.APPLICATION_JSON_VALUE
)
String queryOrder(@RequestParam("access_token") String accessToken,
                  @RequestParam("pay_sig") String paySig,
                  @RequestBody TreeMap requestBody);


### 已排查的问题
1. ✅ AppKey与env匹配:env=1使用沙箱AppKey,env=0使用正式AppKey,无混用;
2. ✅ uri正确性:严格使用 `/xpay/query_order`,无多余参数/路径;
3. ✅ 请求体序列化:使用TreeMap保证字段顺序(openid→env→order_id),JSON序列化无空格/换行;
4. ✅ 签名算法:按官方伪代码实现 `paySig = to_hex(hmac_sha256(appKey,uri + '&' + signData))`;
5. ✅ 参数完整性:openid、env、order_id均非空,与订单数据一致。


最后一次编辑于  03-06
回答关注问题邀请回答
收藏

4 个回答

  • 贺振军
    贺振军
    星期四 14:06

    这个问题解决了吗,我也遇到了同样的问题,同样的签名算法

    Map<String, Object> mapSignData = new LinkedHashMap<>();
    mapSignData.put("openid", memberVirtualOrder.getOpenId());
    mapSignData.put("env", virtualPayEnvironment.getVirtualEnvironment());
    mapSignData.put("order_id", memberVirtualOrder.getOrderId());
    
    logger.info("微信签名数据:{}", mapSignData);
    String paySig = generatePaySign(virtualPayInfo.getAppKey(),"/xpay/query_order", JSON.toJSONString(mapSignData));
    


    这个签名传参和计算,在生成小程序虚拟支付参数时完全正常,下单也成功了,就是调这个接口就出现了签名验证失败的问题

    星期四 14:06
    有用
    回复
  • Memory (私信不回复)
    Memory (私信不回复)
    03-06

    你都用 AI 了,不会让他给你运行一遍你的代码么?

    FeignClient 会序列化 json,你计算是postData,请求时是requestMap,经过FeignClient ,还能保持一致?

    03-06
    有用
    回复
  • 龙
    03-06

    官方文档用的是这个签名方法

    https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/virtual-payment.html#%E6%94%AF%E4%BB%98%E7%AD%BE%E5%90%8D-2

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