前言
最近还是在做微信支付,从之前的图片上传,做到了特约商户进件接口
这个接口真的好多字段啊!!!
就当我信心十足准备调用的时候
悲剧了
返回
"code":"PARAM_ERROR","message":"平台证书序列号Wechatpay-Serial错误
正文
首先推荐大家用微信官方的一个sdk,我把maven
放在这里,这个会帮你做很多事,比如更新证书之类的
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.4.9</version>
</dependency>
引用成功后,就可以使用微信定制的httpclient
进行请求了
第一步:读取商户证书私钥
这里我们可以把商户证书的私钥配置在配置文件中这里就不过多介绍了
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(Files.newInputStream(Paths.get(PrivateKeyPath)));
第二步:创建自动更新签名验证器
verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(MerchantId, new PrivateKeySigner(MerchantSerialNumber, merchantPrivateKey)),
ApiV3key.getBytes(StandardCharsets.UTF_8));
第三步:创建httpclient
httpClient = WechatPayHttpClientBuilder.create()
.withMerchant(MerchantId, MerchantSerialNumber, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier))
.build();
第四步:创建请求对象
这里需要注意一个概念:因为需要对部分字段进行加密进行上传,所以微信需要知道你的平台证书的序列号,才能进行解密!!
这个平台证书是什么?并不是咱们自己申请的证书的序列号,而是上面verifier
调用微信接口获得的平台证书!
AutoUpdateCertificatesVerifier
会自动调用微信的获取平台证书接口,获取证书!
所以接下来,创建请求对象:
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
X509Certificate validCertificate = verifier.getValidCertificate();
httpPost.addHeader("Wechatpay-Serial", String.valueOf(validCertificate.getSerialNumber().toString(16)));
这里一定要对平台证书的序列化进行如下操作,否则会校验不通过
validCertificate.getSerialNumber().toString(16)
我就是因为这个折腾了半天!!!!
第五步:对字段进行加密
使用微信提供的例子,就可以对字段进行加密操作:
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
byte[] data = message.getBytes("utf-8");
byte[] cipherdata = cipher.doFinal(data);
return Base64.getEncoder().encodeToString(cipherdata);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("无效的证书", e);
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
}
其中,certificate
可以通过PemUtil
进行读取
PemUtil.loadCertificate(Files.newInputStream(Paths.get(certificatePath)))
第六步:进行请求:
CloseableHttpResponse response = httpClient.execute(httpPost);
String s = EntityUtils.toString(response.getEntity());
这里注意,可以使用EntityUtils.toString()
来排查,否则返回的code
一直会是400
之类的。
结语
希望能帮助到大家,少走弯路,快速开发!一起加油啊,JYM!!!