小程序支付签名失败,参数都检查过了还是报错?

Air-瑞瑞 阅读 64

用微信小程序支付时,签名一直失败返回”签名错误”。已经确认参数(appid、timestamp等)正确,也按文档排序了参数,但依然报错。签名算法用的是HMAC-SHA1,生成的sign和后端返回的一致吗?

代码示例:


const signStr = Object.keys(params).sort().map(k => <code>${k}=${params[k]}</code>).join('&');
const sign = crypto.createHmac('SHA1', '密钥').update(signStr).digest('hex');

后端返回的prepay_id存在,但wx.requestPayment执行时提示”fail sign error”。是不是时间戳或随机字符串格式有问题?或者参数排序需要排除某些字段?

我来解答 赞 14 收藏
二维码
手机扫码查看
2 条解答
Newb.利云
看了你的代码,问题找到了。微信支付的签名算法根本不是 HMAC-SHA1,这是最大的坑。

微信支付目前支持的签名类型是 MD5 和 HMAC-SHA256(新版V3接口用RSA),你用的 SHA1 完全不对,签名肯定验不过。

还有一个关键点,前端调起支付 wx.requestPayment 的签名参数和后端统一下单的签名参数是两套不同的东西。后端拿到 prepay_id 只是第一步,前端调起支付需要重新生成签名,参数如下:

appId、timeStamp、nonceStr、package(值是 prepay_id=xxx)、signType

这五个字段按字典序拼接,最后拼上商户密钥,用 MD5 或 HMAC-SHA256 生成。注意 timeStamp 要求是秒级时间戳,不是毫秒,这个坑很多人踩过。

正确的签名生成逻辑大概是这样:

const signParams = {
appId: 'your_appid',
timeStamp: String(Math.floor(Date.now() / 1000)),
nonceStr: '随机字符串',
package: prepay_id=${prepay_id},
signType: 'MD5'
};

const signStr = Object.keys(signParams)
.sort()
.map(k => ${k}=${signParams[k]})
.join('&') + '&key=你的商户密钥';

const paySign = md5(signStr).toUpperCase();


实际项目中,这个签名强烈建议让后端生成好直接返回给前端,前端不要碰商户密钥,安全风险太大。后端返回 prepay_id 的时候,顺手把 paySign、timeStamp、nonceStr 一起返回,前端只管调接口就行。

总结一下:算法换成 MD5 或 HMAC-SHA256,时间戳用秒级,签名最好后端生成。改完这些基本就能过了。
点赞 2
2026-03-01 22:08
一树萱
一树萱 Lv1
微信小程序支付的签名算法要用MD5,不是HMAC-SHA1,你得改一下。还有,参数排序时要把空值的字段去掉,timestamp是秒级时间戳,确保格式对了。试试这个代码:

const filterParams = Object.keys(params).reduce((obj, key) => {
if (params[key] !== '' && params[key] != null) {
obj[key] = params[key];
}
return obj;
}, {});
const signStr = Object.keys(filterParams).sort().map(k => ${k}=${filterParams[k]}).join('&') + '&key=你的密钥';
const sign = require('crypto').createHash('md5').update(signStr).digest('hex').toUpperCase();


检查下timestamp是不是秒级的,不是的话除以1000转成秒。再不行就睡一觉明天再调吧,太累了容易出错。
点赞 6
2026-02-15 06:01