2013-10-6 23:20
场景
业务系统经过长时间沉淀积累了许多业务功能模块,我们当前主要工作是在保证日常业务正常进行的前题下对原始功能进行重构、增加新一批业务功能。
我们新加入了一个数据分析对账功能,这个功能需要与第三方支付平台交互进行交易数据采集。线下开发环境测试过程中一切顺利,但正式上线试运行阶段产生了许多http通信相关异常信息,错误信息如下:
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:294)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:200)
at sun.security.validator.Validator.validate(Validator.java:218)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
at com.tvj.iphone.pay.unipay.AuthSSLX509TrustManager.checkServerTrusted(AuthSSLX509TrustManager.java:213)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1066)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:129)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:530)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:465)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:884)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1121)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:623)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:66)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:124)
at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:508)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
at com.tvj.erp.payment.util.httpClient.HttpProtocolHandler.execute(HttpProtocolHandler.java:121)
at com.tvj.erp.payment.util.httpClient.HttpProtocolHandler.execute(HttpProtocolHandler.java:65)
at com.tvj.erp.payment.alipay.AbstractPaymentImpl4Alipay.doRequest(AbstractPaymentImpl4Alipay.java:148)
at com.tvj.erp.payment.alipay.AbstractPaymentImpl4Alipay.innerCollectsPaymentData(AbstractPaymentImpl4Alipay.java:94)
at com.tvj.erp.payment.alipay.AbstractPaymentImpl4Alipay.collectsPaymentData(AbstractPaymentImpl4Alipay.java:82)
at com.tvj.erp.payment.acquis.DefaultPaymentDataAcquisitionStratety.doDataAcquisition(DefaultPaymentDataAcquisitionStratety.java:48)
at com.tvj.erp.payment.PaymentDataAcquisition.doCollectsData(PaymentDataAcquisition.java:60)
... 2 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:289)
... 31 more
分析/处理
很明显从异常信息中可以发现我们集成了Apache HttpClient组件,使用它完成与第三方支付平台的交互。通信协议使用的是HTTPS,单纯从错误信息来看就会把问题划分到证书问题,第三方支付平台证书未被信任,增加相应证书导入操作即可。
顺着这条线索操作完成后,我们发现问题还会在某一时点之后出现,这时问题已经比较明确一些了,服务刚运行起来没有任何问题,但当在某些时点执行或触发了某些业务逻辑操作后就会出现问题。
再次返回到异常日志,发现信任证书这块逻辑处理不是我们这个功能模块所实现的逻辑而是其它功能模块。随及想到了HttpClient#Protocol#有一个全局Map会存储公用的协议实例,当在某一个时点触发这块的逻辑会导致我们正常的证书信任逻辑失效,至此问题解决。
图例
总结
出现这种场景的原因有很多,最直接的原因归结为编码规范问题。