项目中访问支付宝专线踩坑

问题描述

支付宝互联网地址为 https://openapi.alipay.com/gateway.do,专线相比于互联网地址速度更快,更加稳定。这里我们假设专线地址为 https://xxx.xxx.xxx.xxx:443/gateway.do

我们通过支付宝的 SDK 来访问支付宝专线地址,结果报了以下错误

level:ERROR messasge:AbsAlipayService.getResponse.AlipayApiException stackTrack:"com.alipay.api.AlipayApiException: java.io.IOException: HTTPS hostname wrong:  should be <xxx.xxx.xxx.xxx>
    at com.alipay.api.AbstractAlipayClient.doPost(AbstractAlipayClient.java:692)
    at com.alipay.api.AbstractAlipayClient._execute(AbstractAlipayClient.java:607)
    at com.alipay.api.AbstractAlipayClient.execute(AbstractAlipayClient.java:108)
    at com.alipay.api.AbstractAlipayClient.execute(AbstractAlipayClient.java:95)
    at com.alipay.api.AbstractAlipayClient.execute(AbstractAlipayClient.java:89)

问题原因

支付宝 SDK 底层使用 WebUtils 来发送网络请求,HostnameVerifier 实现类默认返回 false,我们需要跳过此验证。

verifier = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return false;
            }
        };

解决方法

方法1

private static void skipAlipayHttpsVerifier() {
        try {
            Field verifierField = WebUtils.class.getDeclaredField("verifier");
            verifierField.setAccessible(true);
            verifierField.set(null, new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            });
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

在项目启动时调用此方法,通过反射来重写 HostnameVerifier 的实现类。

方法2

public abstract class WebUtils {
    private static final String DEFAULT_CHARSET = "UTF-8";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_GET = "GET";
    private static SSLContext ctx = null;
    private static HostnameVerifier verifier = null;
    private static SSLSocketFactory socketFactory = null;

    private WebUtils() {
    }

    static {
        try {
            ctx = SSLContext.getInstance("TLS");
            ctx.init(new KeyManager[0], new TrustManager[]{new DefaultTrustManager()}, new SecureRandom());
            ctx.getClientSessionContext().setSessionTimeout(15);
            ctx.getClientSessionContext().setSessionCacheSize(1000);
            socketFactory = ctx.getSocketFactory();
        } catch (Exception var1) {
        }

        verifier = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
               // 仅修改这一个地方
                return true;
            }
        };
    }
}

在项目中同一个 package 下创建一个 WebUtils,具体类路径为 com.alipay.api.internal.util.WebUtils,这样类加载器最终加载的就是我们自己定义的 WebUtils 类了。

posted @ 2024-04-13 12:55  strongmore  阅读(53)  评论(0编辑  收藏  举报