# 微信小程序虚拟支付 PAY_SIG_INVALID 问题
## 问题描述
在使用 `wx.requestVirtualPayment` 调用虚拟支付时,始终返回 `PAY_SIG_INVALID` 错误,已尝试多种签名计算方式均无法解决。
## 错误信息
- **错误码**:`PAY_SIG_INVALID`
- **错误信息**:`requestVirtualPayment:fail PAY_SIG_INVALID`
- **环境**:正式环境(`env: 1`)
## 基本信息
- **小程序 AppID**:`wx279137ac641a2674`
- **OfferID**:`1450482034`
- **ProductID**:`aa_aa`
- **环境**:正式环境(`env: 1`)
- **AppKey 前缀**:`mBkm`(正式环境,完整长度为 32 位)
## 签名计算方式
根据微信文档,我们使用以下方式计算 `paySig`:
```php
// 方式1:使用 requestVirtualPayment 作为 URI
$uri = 'requestVirtualPayment';
$paySigData = $uri . '&' . $signData;
$paySig = hash_hmac('sha256', $paySigData, $appKey);
// 方式2:使用 /cgi-bin/midas/pay 作为 URI
$uri = '/cgi-bin/midas/pay';
$paySigData = $uri . '&' . $signData;
$paySig = hash_hmac('sha256', $paySigData, $appKey);
// 方式3:直接对 signData 签名
$paySig = hash_hmac('sha256', $signData, $appKey);
```
同时尝试了:
- 十六进制编码(默认)
- Base64 编码
## 实际请求数据
### signData 内容
"buyQuantity": 1,
"env": 1,
"currencyType": "CNY",
"productId": "aa_aa",
"goodsPrice": 100,
"outTradeNo": "VP17724976542266728",
"attach": "{\"vipGrade\":2,\"pricePayType\":\"payMonthly\",\"functiontype\":4}"
### signData 字符串(用于签名)
### paySigData(方式1:requestVirtualPayment)
### paySig 计算结果(方式1,十六进制)
### paySig 计算结果(方式1,Base64)
### paySig 计算结果(方式2,十六进制)
### paySig 计算结果(方式2,Base64)
### paySig 计算结果(方式3,直接签名,十六进制)
### paySig 计算结果(方式3,直接签名,Base64)
## 已尝试的解决方案
1. ✅ 使用 `requestVirtualPayment` 作为 URI 前缀
2. ✅ 使用 `/cgi-bin/midas/pay` 作为 URI 前缀
3. ✅ 直接对 `signData` 签名(不使用 URI 前缀)
4. ✅ 十六进制编码
5. ✅ Base64 编码
6. ✅ 测试环境(`env: 0`)和正式环境(`env: 1`)
7. ✅ 确认 `app_key` 配置正确(正式环境使用正式环境的 `app_key`)
8. ✅ 确认 `signData` 的 JSON 格式正确(字段顺序、转义等)
## 调用代码
### 前端调用
signData: '{"offerId":"1450482034","buyQuantity":1,"env":1,"currencyType":"CNY","productId":"aa_aa","goodsPrice":100,"outTradeNo":"VP17724976542266728","attach":"{\"vipGrade\":2,\"pricePayType\":\"payMonthly\",\"functiontype\":4}"}',
signature: 'b3239b3794df84d2...', // 使用 sessionKey 计算的签名
paySig: 'yKuHKRRzJwFY0OHB...', // 使用 app_key 计算的签名(Base64 版本)
mode: 'short_series_goods'
### 后端签名计算(PHP)
// 用户态签名
$signature = hash_hmac('sha256', $signData, $sessionKey);
// 商户侧签名(paySig)
$uri = 'requestVirtualPayment';
$paySigData = $uri . '&' . $signData;
$paySig = base64_encode(hash_hmac('sha256', $paySigData, $appKey, true));
```
## 后台配置确认
- ✅ `productId` `aa_aa` 已在正式环境发布
- ✅ `goodsPrice` 配置为 100 分(1 元),与代码一致
- ✅ `offerId` `1450482034` 正确
- ✅ `app_key` 已确认是正式环境的密钥
## 问题
1. **`paySig` 的计算方式是否正确?** 是否应该使用 `requestVirtualPayment` 作为 URI,还是 `/cgi-bin/midas/pay`?
2. **`paySig` 的编码格式是什么?** 应该是十六进制还是 Base64?
3. **`signData` 的 JSON 格式是否有特殊要求?** 字段顺序、空格、转义等是否有要求?
4. **是否有其他参数或配置影响签名验证?**
## 期望结果
1. 确认 `paySig` 的正确计算方式
2. 验证我们提供的 `signData` 和 `paySig` 是否正确
3. 提供正确的签名计算示例代码
## 联系方式
- **小程序 AppID**:`wx279137ac641a2674`
- **问题发生时间**:2026-03-03
- **问题环境**:正式环境
---
**注意**:`app_key` 的完整值已脱敏处理,如需完整值进行验证,请通过安全渠道提供。

前端api 下单 uri 为 requestVirtualPayment ,env传0,实测ios传1不行,paySigData 一定是后端json_encode后传入前端用的,如果前端生成的 可能会导致前后端规则不一样 会失败,我们全链路都跑通了 没问题
static function calc_pay_sig($uri, $post_body, $appkey) { $need_sign_msg = $uri . '&' . $post_body; return hash_hmac('sha256', $need_sign_msg, $appkey, false); }不要自己写,把官方文档中的 Demo 丢给 AI 转成你的语言,包通的。
去抄https://developers.weixin.qq.com/community/develop/article/doc/00006845ce4860bedcb4d5eed61813