okhttp报错:clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on jdk 9+

矫情吗;* 2024-03-16 10:00 134阅读 0赞

一、问题现象

最近在用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版本:

  1. <dependency>
  2. <groupId>com.squareup.okhttp3</groupId>
  3. <artifactId>okhttp</artifactId>
  4. <version>4.3.0</version>
  5. </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

  1. <dependency>
  2. <groupId>com.squareup.okio</groupId>
  3. <artifactId>okio</artifactId>
  4. <version>2.8.0</version>
  5. </dependency>

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

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

  1. import javax.net.ssl.*;
  2. import java.security.KeyStore;
  3. import java.security.SecureRandom;
  4. import java.security.cert.X509Certificate;
  5. import java.util.Arrays;
  6. public class SSLSocketClient {
  7. //获取这个SSLSocketFactory
  8. public static SSLSocketFactory getSSLSocketFactory() {
  9. try {
  10. SSLContext sslContext = SSLContext.getInstance("SSL");
  11. sslContext.init(null, getTrustManager(), new SecureRandom());
  12. return sslContext.getSocketFactory();
  13. } catch (Exception e) {
  14. throw new RuntimeException(e);
  15. }
  16. }
  17. //获取TrustManager
  18. private static TrustManager[] getTrustManager() {
  19. return new TrustManager[]{
  20. new X509TrustManager() {
  21. @Override
  22. public void checkClientTrusted(X509Certificate[] chain, String authType) {
  23. }
  24. @Override
  25. public void checkServerTrusted(X509Certificate[] chain, String authType) {
  26. }
  27. @Override
  28. public X509Certificate[] getAcceptedIssuers() {
  29. return new X509Certificate[]{
  30. };
  31. }
  32. }
  33. };
  34. }
  35. //获取HostnameVerifier
  36. public static HostnameVerifier getHostnameVerifier() {
  37. return (s, sslSession) -> true;
  38. }
  39. public static X509TrustManager getX509TrustManager() {
  40. X509TrustManager trustManager = null;
  41. try {
  42. TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
  43. trustManagerFactory.init((KeyStore) null);
  44. TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
  45. if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
  46. throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
  47. }
  48. trustManager = (X509TrustManager) trustManagers[0];
  49. } catch (Exception e) {
  50. e.printStackTrace();
  51. }
  52. return trustManager;
  53. }
  54. }

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

  1. OkHttpClient okHttpClient = new OkHttpClient.Builder()
  2. .readTimeout(60, TimeUnit.SECONDS)
  3. .connectTimeout(60, TimeUnit.SECONDS)
  4. .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.getX509TrustManager())
  5. .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
  6. .build();

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

  1. import okhttp3.*;
  2. import core.SSLSocketClient; //导入上面写的SSLSocketClient类,SSLSocketClient类是放在工程中的core文件夹下
  3. import java.io.IOException;
  4. import java.util.Map;
  5. import java.util.concurrent.TimeUnit;
  6. public class HttpUtils {
  7. private final static MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
  8. private static OkHttpClient client;
  9. private static final Integer DEFAULT_TIMEOUT = 10;
  10. static {
  11. client = new OkHttpClient.Builder()
  12. .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
  13. .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
  14. .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.getX509TrustManager())
  15. .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
  16. .build();
  17. }
  18. public static Response post(String url, Object param, Map<String, String> headers) throws IOException{
  19. if (param instanceof String){
  20. return post(url, (String) param, headers);
  21. } else if (param instanceof Map){
  22. return post(url, (Map<String, String>) param, headers);
  23. }
  24. else {
  25. throw new IOException("没有对的参数类型,请检查");
  26. }
  27. }
  28. private static Response post(String url, String param, Map<String, String> headers) throws IOException{
  29. RequestBody requestBody = RequestBody.create(MEDIA_TYPE, param);
  30. Request.Builder builder = new Request.Builder().url(url);
  31. for (String key : headers.keySet()) {
  32. builder.addHeader(key, headers.get(key));
  33. }
  34. Request request = builder.post(requestBody).build();
  35. return client.newCall(request).execute();
  36. }
  37. private static Response post(String url, Map<String, String> param, Map<String, String> headers) throws IOException{
  38. FormBody.Builder bodyBuilder = new FormBody.Builder();
  39. for (String key: param.keySet()){
  40. bodyBuilder.add(key, param.get(key));
  41. }
  42. RequestBody requestBody = bodyBuilder.build();
  43. Request.Builder builder = new Request.Builder().url(url);
  44. for (String key : headers.keySet()) {
  45. builder.addHeader(key, headers.get(key));
  46. }
  47. Request request = builder.post(requestBody).build();
  48. return client.newCall(request).execute();
  49. }
  50. }

=================================================================================================
以上就是本次的全部内容,如果对你有帮助,麻烦点个赞+收藏+关注,一键三连啦~ 欢迎关注下方我的公众号:程序员杨叔,各类文章都会第一时间在上面发布,持续分享各类测试开发知识干货,你的支持就是作者更新最大的动力。

发表评论

表情:
评论列表 (有 0 条评论,134人围观)

还没有评论,来说两句吧...

相关阅读