暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Okhttp报错:not supported on jdk 9+

程序员杨叔 2023-06-08
292

大家好,我是杨叔。每周进步一点点,关注我的微信公众号【程序员杨叔】,获取更多测试开发技术知识!本次分享的内容是:okhttp报错clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on jdk 9+


一、问题现象



最近在用okHttp处理http请求调用,编写jmeter压测脚本时,出现一个奇怪的问题,idea中可以正常调用。但是打成jar包后,在jmeter中去使用时,则调不通,报错:
clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on jdk 9+, 但是发现自己安装的jdk版本其实就是jdk8。


二、解决方案



经过一番搜索,大概有两种解决办法:
1,使用更低版本的jdk
2,使用更高版本的okHttp(4.3.0版本及以上)

查了一下我项目工程中的OKhttp的版本,果然版本比较低,是3.x版本的。因此使用方法2,项目工程maven里面将okhttp的依赖版本改为4.3.0版本:

    <dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.3.0</version>
    </dependency>

    这样之后再次运行,不再报错:not supported on jdk 9+,但是报另外一个新的错:java.lang.NoSuchFieldError: Companion。
    项目pom.xml文件中,鼠标右键》maven》Show Dependencies,查看各个依赖间的关系图:

    可以看到okhttp与okio关联,网上查了一下原因,是底层依赖 okhttp 与okio的版本不兼容导致,okhttp是 v4.3.0,而okio的版本还是比较低的版本v1.14.0,因此会出现上述问题:

    解决办法就是pom.xml文件中使用更高版本的okio, 比如:V2.8.0

      <dependency>
      <groupId>com.squareup.okio</groupId>
      <artifactId>okio</artifactId>
      <version>2.8.0</version>
      </dependency>

      此后又碰到另外一个问题,当使用jmeter3.2版本时,用上面的方法已经不会报错了。但是当我换成jmeter 5.4.3版本后,还是要继续报:not supported on jdk 9+的错误。

      因此我再尝试下面的做法,然后就不报错了。
      新建一个类SSLSocketClient,代码如下:

        import javax.net.ssl.*;
        import java.security.KeyStore;
        import java.security.SecureRandom;
        import java.security.cert.X509Certificate;
        import java.util.Arrays;


        public class SSLSocketClient {


        获取这个SSLSocketFactory
        public static SSLSocketFactory getSSLSocketFactory() {
        try {
        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, getTrustManager(), new SecureRandom());
        return sslContext.getSocketFactory();
        } catch (Exception e) {
        throw new RuntimeException(e);
        }
        }


        获取TrustManager
        private static TrustManager[] getTrustManager() {
        return new TrustManager[]{
        new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }


        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }


        @Override
        public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[]{};
        }
        }
        };
        }


        获取HostnameVerifier
        public static HostnameVerifier getHostnameVerifier() {
        return (s, sslSession) -> true;
        }


        public static X509TrustManager getX509TrustManager() {
        X509TrustManager trustManager = null;
        try {
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init((KeyStore) null);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
        throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
        }
        trustManager = (X509TrustManager) trustManagers[0];
        } catch (Exception e) {
        e.printStackTrace();
        }


        return trustManager;
        }
        }

        然后OkHttpClient初始化时设置sslSocketFactory和hostnameVerifier,代码如下:

          OkHttpClient okHttpClient = new OkHttpClient.Builder()
          .readTimeout(60, TimeUnit.SECONDS)
          .connectTimeout(60, TimeUnit.SECONDS)


          .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.getX509TrustManager())
          .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
          .build();

          完整的HttpUtils工具类代码如下:

            import okhttp3.*;
            import core.SSLSocketClient; 导入上面写的SSLSocketClient类,SSLSocketClient类是放在工程中的core文件夹下


            import java.io.IOException;
            import java.util.Map;
            import java.util.concurrent.TimeUnit;




            public class HttpUtils {
            private final static MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
            private static OkHttpClient client;
            private static final Integer DEFAULT_TIMEOUT = 10;


            static {
            client = new OkHttpClient.Builder()
            .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.getX509TrustManager())
            .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
            .build();
            }


            public static Response post(String url, Object param, Map<String, String> headers) throws IOException{
            if (param instanceof String){
            return post(url, (String) param, headers);
            } else if (param instanceof Map){
            return post(url, (Map<String, String>) param, headers);
            }
            else {
            throw new IOException("没有对的参数类型,请检查");
            }
            }


            private static Response post(String url, String param, Map<String, String> headers) throws IOException{
            RequestBody requestBody = RequestBody.create(MEDIA_TYPE, param);
            Request.Builder builder = new Request.Builder().url(url);


            for (String key : headers.keySet()) {
            builder.addHeader(key, headers.get(key));
            }
            Request request = builder.post(requestBody).build();
            return client.newCall(request).execute();
            }


            private static Response post(String url, Map<String, String> param, Map<String, String> headers) throws IOException{
            FormBody.Builder bodyBuilder = new FormBody.Builder();
            for (String key: param.keySet()){
            bodyBuilder.add(key, param.get(key));
            }
            RequestBody requestBody = bodyBuilder.build();
            Request.Builder builder = new Request.Builder().url(url);


            for (String key : headers.keySet()) {
            builder.addHeader(key, headers.get(key));
            }
            Request request = builder.post(requestBody).build();
            return client.newCall(request).execute();
            }
            }


            END



            以上就是本次的全部内容,如果对你有帮助,欢迎关注+点赞+分享,你的支持就是作者更新最大的动力!

            欢迎加入杨叔的测试交流群,沟通交流日常测试工作相关内容,三个臭皮匠赛过诸葛亮,2023一起升职加薪,学习进步!可扫码添加杨叔的微信号,备注:进群

            往期精彩文章推荐





            文章转载自程序员杨叔,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

            评论