推荐使用微信支付提供的SDK。你也可以查看下列编程语言的示例代码。
/**
* 获取私钥。
*
* @param filename 私钥文件路径 (required)
* @return 私钥对象
*/
public static PrivateKey getPrivateKey(String filename) throws IOException {
String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
try {
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("无效的密钥格式");
}
}
请根据报文中的message信息,在下表中找到错误的原因和对应的解决方案。
错误描述 | 原因 | 解决方案 |
---|---|---|
商户未设置APIv3密钥。 | 商户未设置APIv3密钥 | 请登录商户平台设置APIv3密钥 |
商户未申请过证书。 | 商户未申请过API证书 | 请参考什么是API证书?如何获取API证书? |
商户证书序列号有误。 | 使用了错误的商户证书,或者使用了已经失效的历史的商户证书,或者获取的商户证书序列号有误 | 请检查商户证书,可登录商户平台查看正确的证书序列号。 |
商户证书已过期。 | 使用了已经过期的商户证书和私钥 | 请到商户平台进行续期,使用续期后的新证书 |
商户证书已作废。 | 使用了商户主动作废的商户证书和私钥 | 请到商户平台重新申请证书后,使用新申请的证书 |
错误的签名,导致验签失败。 | 使用了错误的商户私钥,或签名串构造不正确 | 请见下一问题 |
Http头Authorization值格式错误 | 缺少 Authorization 头,或其格式不正确 |
请检查上送的 Authorization |
Http头Authorization认证类型不正确 | 不支持 Authorization 中声明的签名算法 |
请检查上送的 Authorization ,目前仅支持WECHATPAY2-SHA256-RSA2048 |
Http头Authorization中的timestamp与发起请求的时间不得超过5分钟 | Authorization 头中的时间戳timestamp 所示时间距离当前时间超过5分钟 |
请检查系统时间是否准确,或者获取时间的逻辑是否正确 |
已更换证书,请使用新证书 | 商户主动重新申请了商户API证书 | 请使用新申请的商户API证书 |
为了方便开发者定位,我们对于验签失败,会在应答的错误详情detail
中加入验签信息。验签信息是我们根据商户的HTTP请求构造签名串的各种信息。
method
,HTTP请求方法url
,请求的URLtruncated_sign_message
,微信支付验签时使用的签名串(换行符显示成\n)。为了方便查看,我们对最后的请求报文主体做了截断sign_message_length
,微信支付验签时使用的签名串的字节长度{
"code": "SIGN_ERROR",
"message": "错误的签名,验签失败",
"detail": {
"field": "signature",
"issue": "sign not match",
"location": "authorization",
"sign_information": {
"method": "GET",
"url": "/payscore/user-service-state?service_id=500001&appid=wxeaf7bf1de621b0c2&openid=oWm9Z5JQwgV7BKAQUeKsUMVSjTpQ",
"truncated_sign_message": "GET\n/payscore/user-service-state?service_id=500001&appid=wxeaf7bf1de621b0c2&openid=oWm9Z5JQwgV7BKAQUeKsUMVSjTpQ\n1559194069\n18a427e78d2344e1a71156a2690cc4d6\n\n",
"sign_message_length": 157
}
}
}
建议开发者在程序中将自己组装的签名串以及签名串的字节长度在调试信息中输出,跟微信支付返回的验签信息进行仔细对比,排查以下几种常见的错误:
如果请求报文主体为空(如GET请求),最后一行应为一个换行符。
Authorization
头时,使用了前后生成的两个时间戳Authorization
头时,使用了前后生成的两个不同的随机串。生成签名串使用了非UTF-8编码或者未设置具体编码。
构建签名串没有按照文档要求的顺序进行构建。
开发者可以使用如下的openssl
命令检查私钥和商户证书中的modulus(p、q两个大素数的乘积)是否一致。如果两者一致,那么私钥和证书是成对的。
$ openssl x509 -noout -modulus -in 1900009191_20180326_cert.pem
Modulus=C6D43C87B991...
$ openssl rsa -noout -modulus -in 1900009191_20180326_key.pem
Modulus=C6D43C87B991...
微信支付的回调,在HTTP头部包含了以下四个HTTP头:
某些代理服务器或CDN服务提供商,转发时会“过滤”微信支付扩展的HTTP头,会导致验签的应用层无法取到微信支付的签名信息。遇到这种情况时,建议商户调整代理服务器配置,或者通过直连的方式接受微信支付的回调。