推薦使用微信支付提供的SDK。你也可以查看下列編程語(yǔ)言的示例代碼。
/**
* 獲取私鑰。
*
* @param filename 私鑰文件路徑 (required)
* @return 私鑰對(duì)象
*/
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("當(dāng)前Java環(huán)境不支持RSA", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("無(wú)效的密鑰格式");
}
}
請(qǐng)根據(jù)報(bào)文中的message信息,在下表中找到錯(cuò)誤的原因和對(duì)應(yīng)的解決方案。
錯(cuò)誤描述 | 原因 | 解決方案 |
---|---|---|
商戶未設(shè)置APIv3密鑰。 | 商戶未設(shè)置APIv3密鑰 | 請(qǐng)登錄商戶平臺(tái)設(shè)置APIv3密鑰 |
商戶未申請(qǐng)過證書。 | 商戶未申請(qǐng)過API證書 | 請(qǐng)參考什么是API證書?如何獲取API證書? |
商戶證書序列號(hào)有誤。 | 使用了錯(cuò)誤的商戶證書,或者使用了已經(jīng)失效的歷史的商戶證書,或者獲取的商戶證書序列號(hào)有誤 | 請(qǐng)檢查商戶證書,可登錄商戶平臺(tái)查看正確的證書序列號(hào)。 |
商戶證書已過期。 | 使用了已經(jīng)過期的商戶證書和私鑰 | 請(qǐng)到商戶平臺(tái)進(jìn)行續(xù)期,使用續(xù)期后的新證書 |
商戶證書已作廢。 | 使用了商戶主動(dòng)作廢的商戶證書和私鑰 | 請(qǐng)到商戶平臺(tái)重新申請(qǐng)證書后,使用新申請(qǐng)的證書 |
錯(cuò)誤的簽名,導(dǎo)致驗(yàn)簽失敗。 | 使用了錯(cuò)誤的商戶私鑰,或簽名串構(gòu)造不正確 | 請(qǐng)見下一問題 |
Http頭Authorization值格式錯(cuò)誤 | 缺少 Authorization 頭,或其格式不正確 |
請(qǐng)檢查上送的 Authorization |
Http頭Authorization認(rèn)證類型不正確 | 不支持 Authorization 中聲明的簽名算法 |
請(qǐng)檢查上送的 Authorization ,目前僅支持WECHATPAY2-SHA256-RSA2048 |
Http頭Authorization中的timestamp與發(fā)起請(qǐng)求的時(shí)間不得超過5分鐘 | Authorization 頭中的時(shí)間戳timestamp 所示時(shí)間距離當(dāng)前時(shí)間超過5分鐘 |
請(qǐng)檢查系統(tǒng)時(shí)間是否準(zhǔn)確,或者獲取時(shí)間的邏輯是否正確 |
已更換證書,請(qǐng)使用新證書 | 商戶主動(dòng)重新申請(qǐng)了商戶API證書 | 請(qǐng)使用新申請(qǐng)的商戶API證書 |
為了方便開發(fā)者定位,我們對(duì)于驗(yàn)簽失敗,會(huì)在應(yīng)答的錯(cuò)誤詳情detail
中加入驗(yàn)簽信息。驗(yàn)簽信息是我們根據(jù)商戶的HTTP請(qǐng)求構(gòu)造簽名串的各種信息。
method
,HTTP請(qǐng)求方法url
,請(qǐng)求的URLtruncated_sign_message
,微信支付驗(yàn)簽時(shí)使用的簽名串(換行符顯示成\n)。為了方便查看,我們對(duì)最后的請(qǐng)求報(bào)文主體做了截?cái)?/li>
sign_message_length
,微信支付驗(yàn)簽時(shí)使用的簽名串的字節(jié)長(zhǎng)度{
"code": "SIGN_ERROR",
"message": "錯(cuò)誤的簽名,驗(yàn)簽失敗",
"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
}
}
}
建議開發(fā)者在程序中將自己組裝的簽名串以及簽名串的字節(jié)長(zhǎng)度在調(diào)試信息中輸出,跟微信支付返回的驗(yàn)簽信息進(jìn)行仔細(xì)對(duì)比,排查以下幾種常見的錯(cuò)誤:
如果請(qǐng)求報(bào)文主體為空(如GET請(qǐng)求),最后一行應(yīng)為一個(gè)換行符。
Authorization
頭時(shí),使用了前后生成的兩個(gè)時(shí)間戳Authorization
頭時(shí),使用了前后生成的兩個(gè)不同的隨機(jī)串。生成簽名串使用了非UTF-8編碼或者未設(shè)置具體編碼。
構(gòu)建簽名串沒有按照文檔要求的順序進(jìn)行構(gòu)建。
開發(fā)者可以使用如下的openssl
命令檢查私鑰和商戶證書中的modulus(p、q兩個(gè)大素?cái)?shù)的乘積)是否一致。如果兩者一致,那么私鑰和證書是成對(duì)的。
$ openssl x509 -noout -modulus -in 1900009191_20180326_cert.pem
Modulus=C6D43C87B991...
$ openssl rsa -noout -modulus -in 1900009191_20180326_key.pem
Modulus=C6D43C87B991...
微信支付的回調(diào),在HTTP頭部包含了以下四個(gè)HTTP頭:
某些代理服務(wù)器或CDN服務(wù)提供商,轉(zhuǎn)發(fā)時(shí)會(huì)“過濾”微信支付擴(kuò)展的HTTP頭,會(huì)導(dǎo)致驗(yàn)簽的應(yīng)用層無(wú)法取到微信支付的簽名信息。遇到這種情況時(shí),建議商戶調(diào)整代理服務(wù)器配置,或者通過直連的方式接受微信支付的回調(diào)。