No static field INSTANCE of type Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier;

在Android 9.0中,HttpClient被移除,导致使用依赖于HttpClient的SDK出现错误。博客介绍了如何通过引入cz.msebera.android:httpclient:4.5.8库来替代HttpClient,并修改包名避免冲突,从而解决运行时错误。此外,还提到可以考虑将网络请求替换为UrlConnection或OkHttp作为长期解决方案。

问题背景:

由于使用了宜搭平台作为后台数据存储的地方,而调用宜搭的接口要接入其sdk。但是其xxpt.gateway.shared.client-1.1.4.aar包使用了HttpClient来实现网络访问的,但是在android9时HttpClient被完全移除了,但是这个类还在sdk中而且还基本内容都被删除了:


package org.apache.http.conn.ssl;

/**
 * The ALLOW_ALL HostnameVerifier essentially turns hostname verification
 * off. This implementation is a no-op, and never throws the SSLException.
 * 
 * @author Julius Davies
 *
 * @deprecated Please use {@link java.net.URL#openConnection} instead.
 *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
 *     for further details.
 */
@Deprecated
public class AllowAllHostnameVerifier extends AbstractVerifier {

    public final void verify(
            final String host, 
            final String[] cns,
            final String[] subjectAlts) {
        // Allow everything - so never blowup.
    }

    @Override
    public final String toString() { 
        return "ALLOW_ALL"; 
    }
    
}

普通的HttpClient中的AllowAllHostnameVerifier内容:


package org.apache.http.conn.ssl;

import org.apache.http.annotation.Immutable;

/** @deprecated */
@Deprecated
@Immutable
public class AllowAllHostnameVerifier extends AbstractVerifier {
	//可以知道虽然类也被置为过期的,但INSTANCE静态常量还是在的;
    public static final AllowAllHostnameVerifier INSTANCE = new AllowAllHostnameVerifier();

    public AllowAllHostnameVerifier() {
    }

    public final void verify(String host, String[] cns, String[] subjectAlts) {
    }

    public final String toString() {
        return "ALLOW_ALL";
    }
}

这就有问题了,当xxpt.gateway.shared.client调用AllowAllHostnameVerifier这个文件时访问里边的属性时会访问到AndroidSdk中的这个类AllowAllHostnameVerifier,但是其中的属性已经被删除了,因此就会报No static field INSTANCE这个错误的。

解决方法:

  1. 引入了cz.msebera.android:httpclient:4.5.8这个库代替HttpClient(是类都改了路径,防止xxpt包使用的为正常功能的那个类);
  2. 复制出xxpt中的所有类:在这里插入图片描述

修改其中使用org.apache.http路径的文件为cz.msebera.android.httpclient路径下的类:
在这里插入图片描述

因此app正常了(看着也能把网络请求替换为UrlConnection或okhttp,不过还没深入研究,后期在进行更新)。

package jnpf.util.wxutil; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.ImmutableMap; import jnpf.util.*; import jnpf.util.context.SpringContext; import lombok.Cleanup; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpEntity; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import javax.net.ssl.SSLContext; import java.io.*; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * @author JNPF开发平台组 * @version V3.1.0 * @copyright 引迈信息技术有限公司 * @date 2021/3/16 8:49 */ @Slf4j public class HttpUtil { private HttpUtil() { throw new IllegalAccessError("工具类不能实例化"); } private static PoolingHttpClientConnectionManager connectionManager = null; private static RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(5000) .setConnectTimeout(5000) .setConnectionRequestTimeout(3000) .build(); static { SSLContext sslcontext = SSLContexts.createSystemDefault(); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslcontext)).build(); connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); connectionManager.setMaxTotal(1000); // 每个路由最大的请求数量 connectionManager.setDefaultMaxPerRoute(200); } public static CloseableHttpClient getHttpClient() { return getHttpClientBuilder().build(); } public static CloseableHttpClient getHttpClient(SSLContext sslContext) { return getHttpClientBuilder(sslContext).build(); } public static HttpClientBuilder getHttpClientBuilder() { return HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig); } public static HttpClientBuilder getHttpClientBuilder(SSLContext sslContext) { if (sslContext != null) { return getHttpClientBuilder().setSSLContext(sslContext); } else { return getHttpClientBuilder(); } } /** * post 请求 * * @param httpUrl 请求地址 * @param sslContext ssl证书信息 * @return */ public static String sendHttpPost(String httpUrl, SSLContext sslContext) { // 创建httpPost HttpPost httpPost = new HttpPost(httpUrl); return sendHttpPost(httpPost, sslContext); } /** * 发送 post请求 * * @param httpUrl 地址 */ public static String sendHttpPost(String httpUrl) { // 创建httpPost HttpPost httpPost = new HttpPost(httpUrl); return sendHttpPost(httpPost, null); } /** * 发送 post请求 * * @param httpUrl 地址 * @param params 参数(格式:key1=value1&key2=value2) */ public static String sendHttpPost(String httpUrl, String params) { return sendHttpPost(httpUrl, params, null); } /** * 发送 post请求 * * @param httpUrl 地址 * @param params 参数(格式:key1=value1&key2=value2) * @param sslContext ssl证书信息 */ public static String sendHttpPost(String httpUrl, String params, SSLContext sslContext) { // 创建httpPost HttpPost httpPost = new HttpPost(httpUrl); try { // 设置参数 StringEntity stringEntity = new StringEntity(params, Constants.UTF8); stringEntity.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE); httpPost.setEntity(stringEntity); } catch (Exception e) { log.error(e.getMessage(), e); } return sendHttpPost(httpPost, sslContext); } /** * 发送 post请求 * * @param httpUrl 地址 * @param maps 参数 */ public static String sendHttpPost(String httpUrl, Map<String, String> maps) { return sendHttpPost(httpUrl, maps, null); } /** * 发送 post请求 * * @param httpUrl 地址 * @param maps 参数 * @param sslContext ssl证书信息 */ public static String sendHttpPost(String httpUrl, Map<String, String> maps, SSLContext sslContext) { HttpPost httpPost = wrapHttpPost(httpUrl, maps); return sendHttpPost(httpPost, null); } /** * 封装获取HttpPost方法 * * @param httpUrl * @param maps * @return */ public static HttpPost wrapHttpPost(String httpUrl, Map<String, String> maps) { // 创建httpPost HttpPost httpPost = new HttpPost(httpUrl); // 创建参数队列 List<NameValuePair> nameValuePairs = new ArrayList<>(); for (Map.Entry<String, String> m : maps.entrySet()) { nameValuePairs.add(new BasicNameValuePair(m.getKey(), m.getValue())); } try { httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, Constants.UTF8)); } catch (Exception e) { log.error(e.getMessage(), e); } return httpPost; } /** * 发送 post请求(带文件) * * @param httpUrl 地址 * @param file 附件,名称和File对应 */ public static String sendHttpPost(String httpUrl, File file) { return sendHttpPost(httpUrl, ImmutableMap.of("media", file), null, null); } /** * 发送 post请求(带文件) * * @param httpUrl 地址 * @param file 附件,名称和File对应 * @param maps 参数 */ public static String sendHttpPost(String httpUrl, File file, Map<String, String> maps) { return sendHttpPost(httpUrl, ImmutableMap.of("media", file), maps, null); } /** * 发送 post请求(带文件),默认 files 名称数组. * * @param httpUrl 地址 * @param fileLists 附件 * @param maps 参数 */ public static String sendHttpPost(String httpUrl, List<File> fileLists, Map<String, String> maps) { return sendHttpPost(httpUrl, fileLists, maps, null); } /** * 发送 post请求(带文件) * * @param httpUrl 地址 * @param fileMap 附件,名称和File对应 * @param maps 参数 */ public static String sendHttpPost(String httpUrl, Map<String, File> fileMap, Map<String, String> maps) { return sendHttpPost(httpUrl, fileMap, maps, null); } /** * 发送 post请求(带文件),默认 files 名称数组. * * @param httpUrl 地址 * @param fileLists 附件 * @param maps 参数 * @param sslContext ssl证书信息 */ public static String sendHttpPost(String httpUrl, List<File> fileLists, Map<String, String> maps, SSLContext sslContext) { Map<String, File> fileMap = new HashMap<>(16); if (fileLists == null || fileLists.isEmpty()) { for (File file : fileLists) { fileMap.put("media", file); } } return sendHttpPost(httpUrl, fileMap, maps, sslContext); } /** * 发送 post请求(带文件) * * @param httpUrl 地址 * @param fileMap 附件,名称和File对应 * @param maps 参数 * @param sslContext ssl证书信息 */ public static String sendHttpPost(String httpUrl, Map<String, File> fileMap, Map<String, String> maps, SSLContext sslContext) { // 创建httpPost HttpPost httpPost = new HttpPost(httpUrl); MultipartEntityBuilder meBuilder = MultipartEntityBuilder.create(); if (null != maps) { for (Map.Entry<String, String> m : maps.entrySet()) { meBuilder.addPart(m.getKey(), new StringBody(m.getValue(), ContentType.TEXT_PLAIN)); } } if (null != fileMap) { for (Map.Entry<String, File> m : fileMap.entrySet()) { FileBody fileBody = new FileBody(m.getValue()); meBuilder.addPart(m.getKey(), fileBody); } } HttpEntity reqEntity = meBuilder.build(); httpPost.setEntity(reqEntity); return sendHttpPost(httpPost, sslContext); } /** * 发送Post请求 * * @param httpPost * @return */ public static String sendHttpPost(HttpPost httpPost) { return sendHttpPost(httpPost, null); } /** * 发送Post请求 * * @param httpPost * @param sslConext ssl证书信息 * @return */ public static String sendHttpPost(HttpPost httpPost, SSLContext sslConext) { CloseableHttpClient httpClient = getHttpClient(sslConext); CloseableHttpResponse response = null; HttpEntity entity = null; String responseContent = null; try { // 执行请求 response = httpClient.execute(httpPost); entity = response.getEntity(); responseContent = EntityUtils.toString(entity, Constants.UTF8); } catch (Exception e) { log.error(e.getMessage(), e); } finally { try { // 关闭连接,释放资源 if (entity != null) { // 会自动释放连接 EntityUtils.consumeQuietly(entity); } if (response != null) { response.close(); } } catch (Exception e) { log.error(e.getMessage(), e); } } return responseContent; } /** * 发送 get请求 * * @param httpUrl */ public static String sendHttpGet(String httpUrl) { return sendHttpGet(httpUrl, null); } /** * 发送 get请求 * * @param httpUrl * @param sslConext ssl证书信息 */ public static String sendHttpGet(String httpUrl, SSLContext sslConext) { // 创建get请求 HttpGet httpGet = new HttpGet(httpUrl); return sendHttpGet(httpGet, sslConext); } /** * 发送Get请求 * * @param httpGet * @return */ public static String sendHttpGet(HttpGet httpGet) { return sendHttpGet(httpGet, null); } /** * 发送Get请求 * * @param httpGet * @param sslConext ssl证书信息 * @return */ public static String sendHttpGet(HttpGet httpGet, SSLContext sslConext) { CloseableHttpClient httpClient = getHttpClient(sslConext); CloseableHttpResponse response = null; HttpEntity entity = null; String responseContent = null; try { // 执行请求 response = httpClient.execute(httpGet); entity = response.getEntity(); responseContent = EntityUtils.toString(entity, Constants.UTF8); } catch (Exception e) { log.error(e.getMessage(), e); } finally { try { // 关闭连接,释放资源 if (entity != null) { // 会自动释放连接 EntityUtils.consumeQuietly(entity); } if (response != null) { response.close(); } } catch (Exception e) { log.error(e.getMessage(), e); } } return responseContent; } /** * 发送 get请求 * * @param httpUrl 请求路径 * @param headers 请求头参数 * @return */ public static String sendHttpHeaderGet(String httpUrl, Map<String, String> headers) { // 创建get请求 HttpGet httpGet = new HttpGet(httpUrl); for (Map.Entry<String, String> entry : headers.entrySet()) { String key = entry.getKey().toString(); String value = entry.getValue().toString(); httpGet.setHeader(key, value); } return sendHttpGet(httpGet, null); } /** * Get 下载文件 * * @param httpUrl * @param file * @return */ public static File sendHttpGetFile(String httpUrl, File file) { if (file == null) { return null; } HttpGet httpGet = new HttpGet(httpUrl); CloseableHttpClient httpClient = getHttpClient(); CloseableHttpResponse response = null; HttpEntity entity = null; InputStream inputStream = null; FileOutputStream fileOutputStream = null; try { // 执行请求 response = httpClient.execute(httpGet); entity = response.getEntity(); inputStream = entity.getContent(); fileOutputStream = new FileOutputStream(file); int len = 0; byte[] buf = new byte[1024]; while ((len = inputStream.read(buf, 0, 1024)) != -1) { fileOutputStream.write(buf, 0, len); } } catch (Exception e) { log.error(e.getMessage(), e); } finally { try { if (fileOutputStream != null) { fileOutputStream.close(); } if (inputStream != null) { inputStream.close(); } // 关闭连接,释放资源 if (entity != null) { // 会自动释放连接 EntityUtils.consumeQuietly(entity); } if (response != null) { response.close(); } } catch (Exception e) { log.error(e.getMessage(), e); } } return file; } /** * Post 下载文件 * * @param httpUrl * @param maps * @param file * @return */ public static File sendHttpPostFile(String httpUrl, Map<String, String> maps, File file) { if (file == null) { return null; } HttpPost httpPost = wrapHttpPost(httpUrl, maps); CloseableHttpClient httpClient = getHttpClient(); CloseableHttpResponse response = null; HttpEntity entity = null; InputStream inputStream = null; FileOutputStream fileOutputStream = null; try { // 执行请求 response = httpClient.execute(httpPost); entity = response.getEntity(); inputStream = entity.getContent(); fileOutputStream = new FileOutputStream(file); int len = 0; byte[] buf = new byte[1024]; while ((len = inputStream.read(buf, 0, 1024)) != -1) { fileOutputStream.write(buf, 0, len); } } catch (Exception e) { log.error(e.getMessage(), e); } finally { try { if (fileOutputStream != null) { fileOutputStream.close(); } if (inputStream != null) { inputStream.close(); } // 关闭连接,释放资源 if (entity != null) { // 会自动释放连接 EntityUtils.consumeQuietly(entity); } if (response != null) { response.close(); } } catch (Exception e) { log.error(e.getMessage(), e); } } return file; } /** * 判断是否微信返回错误 * * @param jsonObject * @return */ public static boolean isWxError(JSONObject jsonObject) { if (null == jsonObject || jsonObject.getIntValue("errcode") != 0) { return true; } return false; } /** * http请求 * * @param requestUrl url * @param requestMethod GET/POST * @param outputStr 参数 * @return */ public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) { return httpRequest(requestUrl,requestMethod,outputStr,null); } /** * http请求 * * @param requestUrl url * @param requestMethod GET/POST * @param outputStr 参数 * @return */ public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr, String... token) { JSONObject jsonObject = null; try { URL url = new URL(requestUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); conn.setRequestMethod(requestMethod); conn.setConnectTimeout(50000); conn.setReadTimeout(60000); if (token != null && token.length > 2 && token[2] != null) { if ("1".equals(token[2])) { conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE); } else if ("2".equals(token[2])) { conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE); } else if ("3".equals(token[2])) { conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); } else if ("4".equals(token[2])) { conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE); } else { conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); } } else { conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); } if (token != null && token.length > 0 && StringUtil.isNotEmpty(token[0])) { conn.setRequestProperty(Constants.AUTHORIZATION, XSSEscape.escape(token[0])); } // 处理请求头参数 if (token != null && token.length > 1 && StringUtil.isNotEmpty(token[1])) { Map<String, Object> requestHeader = JsonUtil.stringToMap(token[1]); for (String field : requestHeader.keySet()) { conn.setRequestProperty(field, requestHeader.get(field) + ""); } } String agent = ServletUtil.getUserAgent(); if (StringUtil.isNotEmpty(agent)) { conn.setRequestProperty(Constants.USER_AGENT, agent); } if (StringUtil.isNotEmpty(outputStr)) { @Cleanup OutputStream outputStream = conn.getOutputStream(); outputStream.write(outputStr.getBytes(Constants.UTF8)); outputStream.close(); } @Cleanup InputStream inputStream = conn.getInputStream(); @Cleanup InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Constants.UTF8); @Cleanup BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } bufferedReader.close(); inputStreamReader.close(); inputStream.close(); conn.disconnect(); jsonObject = JSONObject.parseObject(buffer.toString()); if (jsonObject == null) { return new JSONObject(); } } catch (Exception e) { log.error(e.getMessage()); } return jsonObject; } /** * http请求 * * @param requestUrl url * @param requestMethod GET/POST * @param outputStr 参数 * @return */ public static boolean httpCronRequest(String requestUrl, String requestMethod, String outputStr, String token) { boolean falg = false; try { URL url = new URL(requestUrl); final HttpURLConnection[] conn = {null}; Callable<String> task = new Callable<String>() { @Override public String call() throws Exception { //执行耗时代码 try { conn[0] = (HttpURLConnection) url.openConnection(); } catch (Exception e) { log.error(e.getMessage()); } conn[0].setDoOutput(true); conn[0].setDoInput(true); conn[0].setUseCaches(false); conn[0].setRequestMethod(requestMethod); conn[0].setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); if (StringUtil.isNotEmpty(token)) { conn[0].setRequestProperty(Constants.AUTHORIZATION, token); } if (null != outputStr) { @Cleanup OutputStream outputStream = conn[0].getOutputStream(); outputStream.write(outputStr.getBytes(Constants.UTF8)); outputStream.close(); } @Cleanup InputStream inputStream = conn[0].getInputStream(); @Cleanup InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Constants.UTF8); @Cleanup BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } bufferedReader.close(); inputStreamReader.close(); inputStream.close(); conn[0].disconnect(); return "url连接ok"; } }; Future<String> future = ThreadPoolExecutorUtil.getExecutor().submit(task); try { //设置超时时间 String rst = future.get(3, TimeUnit.SECONDS); if ("url连接ok".equals(rst)) { falg = true; } } catch (TimeoutException e) { log.error("连接url超时"); } catch (Exception e) { log.error("获取异常," + e.getMessage()); } } catch (MalformedURLException e) { e.printStackTrace(); } return falg; } } // // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.http; import java.io.Serializable; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.InvalidMimeTypeException; import org.springframework.util.MimeType; import org.springframework.util.MimeTypeUtils; import org.springframework.util.StringUtils; public class MediaType extends MimeType implements Serializable { private static final long serialVersionUID = 2069937152339670231L; public static final MediaType ALL = new MediaType("*", "*"); public static final String ALL_VALUE = "*/*"; public static final MediaType APPLICATION_ATOM_XML = new MediaType("application", "atom+xml"); public static final String APPLICATION_ATOM_XML_VALUE = "application/atom+xml"; public static final MediaType APPLICATION_CBOR = new MediaType("application", "cbor"); public static final String APPLICATION_CBOR_VALUE = "application/cbor"; public static final MediaType APPLICATION_FORM_URLENCODED = new MediaType("application", "x-www-form-urlencoded"); public static final String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded"; /** @deprecated */ @Deprecated( since = "6.0.3", forRemoval = true ) public static final MediaType APPLICATION_GRAPHQL = new MediaType("application", "graphql+json"); /** @deprecated */ @Deprecated( since = "6.0.3", forRemoval = true ) public static final String APPLICATION_GRAPHQL_VALUE = "application/graphql+json"; public static final MediaType APPLICATION_GRAPHQL_RESPONSE = new MediaType("application", "graphql-response+json"); public static final String APPLICATION_GRAPHQL_RESPONSE_VALUE = "application/graphql-response+json"; public static final MediaType APPLICATION_JSON = new MediaType("application", "json"); public static final String APPLICATION_JSON_VALUE = "application/json"; /** @deprecated */ @Deprecated public static final MediaType APPLICATION_JSON_UTF8; /** @deprecated */ @Deprecated public static final String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8"; public static final MediaType APPLICATION_OCTET_STREAM; public static final String APPLICATION_OCTET_STREAM_VALUE = "application/octet-stream"; public static final MediaType APPLICATION_PDF; public static final String APPLICATION_PDF_VALUE = "application/pdf"; public static final MediaType APPLICATION_PROBLEM_JSON; public static final String APPLICATION_PROBLEM_JSON_VALUE = "application/problem+json"; /** @deprecated */ @Deprecated public static final MediaType APPLICATION_PROBLEM_JSON_UTF8; /** @deprecated */ @Deprecated public static final String APPLICATION_PROBLEM_JSON_UTF8_VALUE = "application/problem+json;charset=UTF-8"; public static final MediaType APPLICATION_PROBLEM_XML; public static final String APPLICATION_PROBLEM_XML_VALUE = "application/problem+xml"; public static final MediaType APPLICATION_PROTOBUF; public static final String APPLICATION_PROTOBUF_VALUE = "application/x-protobuf"; public static final MediaType APPLICATION_RSS_XML; public static final String APPLICATION_RSS_XML_VALUE = "application/rss+xml"; public static final MediaType APPLICATION_NDJSON; public static final String APPLICATION_NDJSON_VALUE = "application/x-ndjson"; /** @deprecated */ @Deprecated public static final MediaType APPLICATION_STREAM_JSON; /** @deprecated */ @Deprecated public static final String APPLICATION_STREAM_JSON_VALUE = "application/stream+json"; public static final MediaType APPLICATION_XHTML_XML; public static final String APPLICATION_XHTML_XML_VALUE = "application/xhtml+xml"; public static final MediaType APPLICATION_XML; public static final String APPLICATION_XML_VALUE = "application/xml"; public static final MediaType APPLICATION_YAML; public static final String APPLICATION_YAML_VALUE = "application/yaml"; public static final MediaType IMAGE_GIF; public static final String IMAGE_GIF_VALUE = "image/gif"; public static final MediaType IMAGE_JPEG; public static final String IMAGE_JPEG_VALUE = "image/jpeg"; public static final MediaType IMAGE_PNG; public static final String IMAGE_PNG_VALUE = "image/png"; public static final MediaType MULTIPART_FORM_DATA; public static final String MULTIPART_FORM_DATA_VALUE = "multipart/form-data"; public static final MediaType MULTIPART_MIXED; public static final String MULTIPART_MIXED_VALUE = "multipart/mixed"; public static final MediaType MULTIPART_RELATED; public static final String MULTIPART_RELATED_VALUE = "multipart/related"; public static final MediaType TEXT_EVENT_STREAM; public static final String TEXT_EVENT_STREAM_VALUE = "text/event-stream"; public static final MediaType TEXT_HTML; public static final String TEXT_HTML_VALUE = "text/html"; public static final MediaType TEXT_MARKDOWN; public static final String TEXT_MARKDOWN_VALUE = "text/markdown"; public static final MediaType TEXT_PLAIN; public static final String TEXT_PLAIN_VALUE = "text/plain"; public static final MediaType TEXT_XML; public static final String TEXT_XML_VALUE = "text/xml"; private static final String PARAM_QUALITY_FACTOR = "q"; /** @deprecated */ @Deprecated( since = "6.0", forRemoval = true ) public static final Comparator<MediaType> QUALITY_VALUE_COMPARATOR; /** @deprecated */ @Deprecated( since = "6.0", forRemoval = true ) public static final Comparator<MediaType> SPECIFICITY_COMPARATOR; public MediaType(String type) { super(type); } public MediaType(String type, String subtype) { super(type, subtype, Collections.emptyMap()); } public MediaType(String type, String subtype, Charset charset) { super(type, subtype, charset); } public MediaType(String type, String subtype, double qualityValue) { this(type, subtype, Collections.singletonMap("q", Double.toString(qualityValue))); } public MediaType(MediaType other, Charset charset) { super(other, charset); } public MediaType(MediaType other, @Nullable Map<String, String> parameters) { super(other.getType(), other.getSubtype(), parameters); } public MediaType(String type, String subtype, @Nullable Map<String, String> parameters) { super(type, subtype, parameters); } public MediaType(MimeType mimeType) { super(mimeType); this.getParameters().forEach(this::checkParameters); } protected void checkParameters(String parameter, String value) { super.checkParameters(parameter, value); if ("q".equals(parameter)) { String unquotedValue = this.unquote(value); double d = Double.parseDouble(unquotedValue); Assert.isTrue(d >= (double)0.0F && d <= (double)1.0F, () -> "Invalid quality value \"" + unquotedValue + "\": should be between 0.0 and 1.0"); } } public double getQualityValue() { String qualityFactor = this.getParameter("q"); return qualityFactor != null ? Double.parseDouble(this.unquote(qualityFactor)) : (double)1.0F; } public boolean isMoreSpecific(MimeType other) { Assert.notNull(other, "Other must not be null"); if (other instanceof MediaType otherMediaType) { double quality1 = this.getQualityValue(); double quality2 = otherMediaType.getQualityValue(); if (quality1 > quality2) { return true; } if (quality1 < quality2) { return false; } } return super.isMoreSpecific(other); } public boolean isLessSpecific(MimeType other) { Assert.notNull(other, "Other must not be null"); return other.isMoreSpecific(this); } public boolean includes(@Nullable MediaType other) { return super.includes(other); } public boolean isCompatibleWith(@Nullable MediaType other) { return super.isCompatibleWith(other); } public MediaType copyQualityValue(MediaType mediaType) { if (!mediaType.getParameters().containsKey("q")) { return this; } else { Map<String, String> params = new LinkedHashMap(this.getParameters()); params.put("q", (String)mediaType.getParameters().get("q")); return new MediaType(this, params); } } public MediaType removeQualityValue() { if (!this.getParameters().containsKey("q")) { return this; } else { Map<String, String> params = new LinkedHashMap(this.getParameters()); params.remove("q"); return new MediaType(this, params); } } public static MediaType valueOf(String value) { return parseMediaType(value); } public static MediaType parseMediaType(String mediaType) { MimeType type; try { type = MimeTypeUtils.parseMimeType(mediaType); } catch (InvalidMimeTypeException ex) { throw new InvalidMediaTypeException(ex); } try { return new MediaType(type); } catch (IllegalArgumentException ex) { throw new InvalidMediaTypeException(mediaType, ex.getMessage()); } } public static List<MediaType> parseMediaTypes(@Nullable String mediaTypes) { if (!StringUtils.hasLength(mediaTypes)) { return Collections.emptyList(); } else { List<String> tokenizedTypes = MimeTypeUtils.tokenize(mediaTypes); List<MediaType> result = new ArrayList(tokenizedTypes.size()); for(String type : tokenizedTypes) { if (StringUtils.hasText(type)) { result.add(parseMediaType(type)); } } return result; } } public static List<MediaType> parseMediaTypes(@Nullable List<String> mediaTypes) { if (CollectionUtils.isEmpty(mediaTypes)) { return Collections.emptyList(); } else if (mediaTypes.size() == 1) { return parseMediaTypes((String)mediaTypes.get(0)); } else { List<MediaType> result = new ArrayList(8); for(String mediaType : mediaTypes) { result.addAll(parseMediaTypes(mediaType)); } return result; } } public static List<MediaType> asMediaTypes(List<MimeType> mimeTypes) { List<MediaType> mediaTypes = new ArrayList(mimeTypes.size()); for(MimeType mimeType : mimeTypes) { mediaTypes.add(asMediaType(mimeType)); } return mediaTypes; } public static MediaType asMediaType(MimeType mimeType) { if (mimeType instanceof MediaType mediaType) { return mediaType; } else { return new MediaType(mimeType.getType(), mimeType.getSubtype(), mimeType.getParameters()); } } public static String toString(Collection<MediaType> mediaTypes) { return MimeTypeUtils.toString(mediaTypes); } /** @deprecated */ @Deprecated( since = "6.0", forRemoval = true ) public static void sortBySpecificity(List<MediaType> mediaTypes) { Assert.notNull(mediaTypes, "'mediaTypes' must not be null"); if (mediaTypes.size() > 1) { mediaTypes.sort(SPECIFICITY_COMPARATOR); } } /** @deprecated */ @Deprecated( since = "6.0", forRemoval = true ) public static void sortByQualityValue(List<MediaType> mediaTypes) { Assert.notNull(mediaTypes, "'mediaTypes' must not be null"); if (mediaTypes.size() > 1) { mediaTypes.sort(QUALITY_VALUE_COMPARATOR); } } /** @deprecated */ @Deprecated( since = "6.0", forRemoval = true ) public static void sortBySpecificityAndQuality(List<MediaType> mediaTypes) { Assert.notNull(mediaTypes, "'mediaTypes' must not be null"); if (mediaTypes.size() > 1) { mediaTypes.sort(SPECIFICITY_COMPARATOR.thenComparing(QUALITY_VALUE_COMPARATOR)); } } static { APPLICATION_JSON_UTF8 = new MediaType("application", "json", StandardCharsets.UTF_8); APPLICATION_NDJSON = new MediaType("application", "x-ndjson"); APPLICATION_OCTET_STREAM = new MediaType("application", "octet-stream"); APPLICATION_PDF = new MediaType("application", "pdf"); APPLICATION_PROBLEM_JSON = new MediaType("application", "problem+json"); APPLICATION_PROBLEM_JSON_UTF8 = new MediaType("application", "problem+json", StandardCharsets.UTF_8); APPLICATION_PROBLEM_XML = new MediaType("application", "problem+xml"); APPLICATION_PROTOBUF = new MediaType("application", "x-protobuf"); APPLICATION_RSS_XML = new MediaType("application", "rss+xml"); APPLICATION_STREAM_JSON = new MediaType("application", "stream+json"); APPLICATION_XHTML_XML = new MediaType("application", "xhtml+xml"); APPLICATION_XML = new MediaType("application", "xml"); APPLICATION_YAML = new MediaType("application", "yaml"); IMAGE_GIF = new MediaType("image", "gif"); IMAGE_JPEG = new MediaType("image", "jpeg"); IMAGE_PNG = new MediaType("image", "png"); MULTIPART_FORM_DATA = new MediaType("multipart", "form-data"); MULTIPART_MIXED = new MediaType("multipart", "mixed"); MULTIPART_RELATED = new MediaType("multipart", "related"); TEXT_EVENT_STREAM = new MediaType("text", "event-stream"); TEXT_HTML = new MediaType("text", "html"); TEXT_MARKDOWN = new MediaType("text", "markdown"); TEXT_PLAIN = new MediaType("text", "plain"); TEXT_XML = new MediaType("text", "xml"); QUALITY_VALUE_COMPARATOR = (mediaType1, mediaType2) -> { double quality1 = mediaType1.getQualityValue(); double quality2 = mediaType2.getQualityValue(); int qualityComparison = Double.compare(quality2, quality1); if (qualityComparison != 0) { return qualityComparison; } else if (mediaType1.isWildcardType() && !mediaType2.isWildcardType()) { return 1; } else if (mediaType2.isWildcardType() && !mediaType1.isWildcardType()) { return -1; } else if (!mediaType1.getType().equals(mediaType2.getType())) { return 0; } else if (mediaType1.isWildcardSubtype() && !mediaType2.isWildcardSubtype()) { return 1; } else if (mediaType2.isWildcardSubtype() && !mediaType1.isWildcardSubtype()) { return -1; } else if (!mediaType1.getSubtype().equals(mediaType2.getSubtype())) { return 0; } else { int paramsSize1 = mediaType1.getParameters().size(); int paramsSize2 = mediaType2.getParameters().size(); return Integer.compare(paramsSize2, paramsSize1); } }; SPECIFICITY_COMPARATOR = new MimeType.SpecificityComparator<MediaType>() { protected int compareParameters(MediaType mediaType1, MediaType mediaType2) { double quality1 = mediaType1.getQualityValue(); double quality2 = mediaType2.getQualityValue(); int qualityComparison = Double.compare(quality2, quality1); return qualityComparison != 0 ? qualityComparison : super.compareParameters(mediaType1, mediaType2); } }; } }
最新发布
09-09
<think>好的,我现在需要解决用户提到的Java中的NoSuchFieldError错误,具体是org/apache/http/conn/ssl/AllowAllHostnameVerifier.INSTANCE的问题。首先,我得回忆一下这个错误通常是什么原因引起的。用户之前的问题是关于GitLab邮件服务器配置的,现在转向Java依赖问题,可能他是在开发过程中遇到了这个问题,可能是在使用Apache HttpClient库时出现的。 首先,这个错误提示的是找不到AllowAllHostnameVerifier类的INSTANCE字段。根据经验,NoSuchFieldError通常是因为类版本不兼容,编译时存在某个字段,但运行时加载的类版本中没有这个字段。所以,我需要检查Apache HttpClient的不同版本中这个类的情况。 接下来,我需要确认用户使用的HttpClient版本。AllowAllHostnameVerifier这个类在HttpClient 4.x中存在吗?比如,在4.3版本中,我记得SSL相关的类可能有变化。比如,HttpClient 4.3之后可能移除了这个类,或者将其标记为过时,而改用其他方式处理主机名验证。 例如,在旧版本的HttpClient中,比如4.2或更早,AllowAllHostnameVerifier可能有INSTANCE这个静态实例。而在4.3或更高版本中,可能已经弃用了这个类,或者将其重构,导致该字段不存在。因此,当用户的项目中依赖了不同版本的库,特别是可能存在多个版本的冲突时,就会引发这个问题。 用户可能在代码中直接引用了AllowAllHostnameVerifier.INSTANCE,而在新版本的HttpClient中,这个字段已经被移除或者替换了。比如,新版本可能推荐使用NoopHostnameVerifier.INSTANCE来代替,或者使用其他方式关闭主机名验证。 解决方法可能包括: 1. 检查依赖版本:确保所有依赖的HttpClient相关库版本一致,没有冲突。比如,httpclient和httpcore的版本是否匹配,是否有其他库引入了旧版本的HttpClient。 2. 替换过时的类:如果用户正在使用高版本的HttpClient,可能需要将AllowAllHostnameVerifier替换为NoopHostnameVerifier,或者调整代码使用新的API。 3. 调整依赖管理:如果项目中使用了Maven或Gradle,需要排除冲突的依赖,强制使用正确的版本。 另外,用户可能在升级Spring Boot或者其他框架时,间接引入了新版本的HttpClient,导致旧代码中的类不再存在。这时候需要调整代码以适应新版本,或者降级到兼容的HttpClient版本。 还需要考虑是否有其他库依赖了旧版本的HttpClient,比如旧的第三方库可能引入了4.2版本,而用户的项目依赖了4.5版本,导致类加载时出现冲突。这时候需要排除旧版本的依赖。 总结步骤应该是: - 确认当前项目中的HttpClient版本。 - 检查是否有多个版本的HttpClient被引入,导致冲突。 - 根据版本调整代码,替换过时的类或方法。 - 使用依赖管理工具排除冲突的版本,确保统一使用兼容的版本。 同时,需要提供具体的示例代码,比如如何修改HostnameVerifier的使用,以及Maven或Gradle中如何排除依赖等。这样用户可以直接应用这些解决方案。 可能还需要提醒用户,禁用主机名验证(比如使用AllowAllHostnameVerifierNoopHostnameVerifier)在生产环境中是不安全的,建议仅在测试环境中使用,并正确配置SSL证书以避免安全问题。</think>以下是关于$`java.lang.NoSuchFieldError: org.apache.http.conn.ssl.AllowAllHostnameVerifier.INSTANCE`$错误的详细分析和解决方案: --- ### 一、错误原因解析 该错误是由于**Apache HttpClient版本冲突**导致的,具体表现为: 1. **类定义不匹配**:代码中引用的$`AllowAllHostnameVerifier.INSTANCE`$字段在高版本HttpClient(4.3+)中已被移除[^1] 2. **依赖冲突**:项目中同时存在多个HttpClient版本(例如Spring Boot依赖管理自动升级了版本) 3. **API弃用**:$`AllowAllHostnameVerifier`$自HttpClient 4.3起被标记为@Deprecated,4.5+版本完全移除[^2] --- ### 二、解决方案 #### ▶ 方案1:统一依赖版本(推荐) 在构建工具中强制指定HttpClient版本(以Maven为例): ```xml <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.2.6</version> <!-- 保留旧版API --> </dependency> ``` #### ▶ 方案2:修改代码适配新版API 若必须使用高版本HttpClient(4.3+),改用$`NoopHostnameVerifier`$: ```java // 原代码 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslContext, new String[]{"TLSv1.2"}, null, AllowAllHostnameVerifier.INSTANCE // 已过时 ); // 修改后 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslContext, new String[]{"TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE // 新API ); ``` #### ▶ 方案3:排除冲突依赖 当Spring Boot导致版本冲突时,在pom.xml中添加: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </exclusion> </exclusions> </dependency> ``` --- ### 三、验证步骤 1. 查看实际加载的依赖版本: ```bash mvn dependency:tree | grep httpclient ``` 2. 检查代码中所有使用$`HostnameVerifier`$的地方是否适配当前版本 --- ### 四、安全警告 $$ \textcolor{red}{\text{使用NoopHostnameVerifier会禁用SSL主机名验证,仅限测试环境使用!}} $$ 生产环境应配置有效证书或使用: ```java SSLConnectionSocketFactory sslsf = SSLConnectionSocketFactory.createDefault(); ``` ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值