IJPay微信退款协议不正确 No appropriate protocol
目录问题发现问题研究解决方案问题发现项目中有微信支付功能,也可以微信退款,因为自己写支付代码比较臃肿,所以用了第三方包IJPay来实现支付和退款功能,它封装了一些第三方支付的方法,比如支付宝、微信、银联,使用了一年多没有问题,前端时间突然使用微信退款功能时报错:cn.hutool.core.io.IORuntimeException: SSLHandshakeException: No appro
问题发现
项目中有微信支付功能,也可以微信退款,因为自己写支付代码比较臃肿,所以用了第三方包IJPay来实现支付和退款功能,它封装了一些第三方支付的方法,比如支付宝、微信、银联,使用了一年多没有问题,前端时间突然使用微信退款功能时报错:
cn.hutool.core.io.IORuntimeException: SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
问题研究
上网搜索发现微信社区看到也有人出同样的错:微信社区链接
百度上搜索也有人说是jdk版本问题的,但是我这个一开始没错所以我觉得不关jdk的问题,也没有往这方面研究,然后我找到IJPay的码云Issues:IJPay码云链接
里面也有人提到这个问题,IJPay作者也发现了,提供了版本升级,之前退款用的方法是orderRefund,现在加了一个orderRefundByProtocol方法,可以自己手动输入协议,我想这个问题肯定立马解决了,测试orderRefundByProtocol方法的协议填null,报空指针异常,填“”、“SSLv3”、“SSLv2”均报以上同样的错误(No appropriate protocol)
就觉得很奇怪,然后追溯IJPay的源码:
// 1.自己的业务代码
String refundStr = WxPayApi.orderRefundByProtocol(false, params, certPath, account.getMchid(),"");
// 2
public static String orderRefundByProtocol(boolean isSandbox, Map<String, String> params, String certPath, String certPass, String protocol) {
return execution(getReqUrl(WxApiType.REFUND, (WxDomain)null, isSandbox), params, certPath, certPass, protocol);
}
// 3.此方法中的参数filePath为上一步中的参数protocol
public static String execution(String apiUrl, Map<String, String> params, String certPath, String certPass, String filePath) {
return doUploadSsl(apiUrl, params, certPath, certPass, filePath);
}
// 4. 此方法参数filePath实际为protocol
public static String doUploadSsl(String url, Map<String, String> params, String certPath, String certPass, String filePath) {
return HttpKit.getDelegate().upload(url, WxPayKit.toXml(params), certPath, certPass, filePath);
}
// 5.
public String upload(String url, String data, String certPath, String certPass, String filePath) {
return this.upload(url, data, certPath, certPass, filePath, "TLSv1");
}
// 6.此方法中的protocol为5步骤中的代码写死的“TLSv1”,那么是否实际执行的时候还是用的TLSv1协议,而不是自己参数里面写的协议
public String upload(String url, String data, String certPath, String certPass, String filePath, String protocol) {
try {
File file = FileUtil.newFile(filePath);
return ((HttpRequest)HttpRequest.post(url).setSSLSocketFactory(SSLSocketFactoryBuilder.create().setProtocol(protocol).setKeyManagers(this.getKeyManager(certPass, certPath, (InputStream)null)).setSecureRandom(new SecureRandom()).build()).header("Content-Type", "multipart/form-data;boundary=\"boundary\"")).form("file", file).form("meta", data).execute().body();
} catch (Exception var8) {
throw new RuntimeException(var8);
}
}
以上是orderRefundByProtocol方法的调用链路,我发现可能是这个方法根本没有用上自己填写的协议,一筹莫展,如果抛弃IJPay重写代码的话,花费的时间较多,因为项目已发布在线上也怕出错,所以只好先在IJPay的Issues里面提了自己的问题,希望作者能给与解决办法,正当我想要放弃,等待作者解决办法的时候,我想到用IJPay里面封装的底层方法。
解决方案
通过以上源码追溯,orderRefund方法中调用的AbstractHttpDelegate这个抽象类的post方法,IJPay是写死的“TLSv1”,我们只需要单独调用这个方法,把里面的协议直接填写""就行了,贴上代码:
// 自己的业务代码
String refundStr = HttpKit.getDelegate().post(WxPayApi.getReqUrl(WxApiType.REFUND, (WxDomain) null, false), WxPayKit.toXml(params), certPath, account.getMchid(), "");
// 实际调用AbstractHttpDelegate类中的方法
public String post(String url, String data, String certPath, String certPass, String protocol) {
try {
return HttpRequest.post(url).setSSLSocketFactory(SSLSocketFactoryBuilder.create().setProtocol(protocol).setKeyManagers(this.getKeyManager(certPass, certPath, (InputStream)null)).setSecureRandom(new SecureRandom()).build()).body(data).execute().body();
} catch (Exception var7) {
throw new RuntimeException(var7);
}
}
没有悬念,一下就成功了!
更多推荐
所有评论(0)