Есть ли обходной путь для этого исключения? глядя на этот проблема на github, похоже, что это может быть ошибка Android, что-то о имени хоста, имеющем символ подчеркивания или что-то в этом роде.
Это трассировка стека:
javax.net.ssl.SSLHandshakeException: java.lang.IllegalArgumentException: Invalid input to toASCII: ip_nbae7bac35.kodrive.xyz
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:219)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:318)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:282)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:167)
at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257)
at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
at okhttp3.RealCall.execute(RealCall.java:77)
Ваша проблема в том, что вы не можете преобразовать строку в ASCII, используя toASCII, который содержит _. Нет другого выхода, кроме как связаться с владельцем домена и попросить его удалить _. Вот почему у вас IllegalArgumentException, строка была "недопустимой".
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* 忽略https证书验证
*/
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() {
TrustManager[] trustAllCerts = 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[]{};
}
}};
return trustAllCerts;
}
//获取HostnameVerifier
public static HostnameVerifier getHostnameVerifier() {
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
};
return hostnameVerifier;
}
}
OkHttpClient.Builder builder = ...
builder.sslSocketFactory(SSLSocketClient.getSSLSocketFactory())
.hostnameVerifier(SSLSocketClient.getHostnameVerifier())
Не могли бы вы добавить к своему ответу более подробную информацию? Чем он отличается от принятого ответа?
Я не публиковал этот ответ, но в основном он принимает все имена хостов, которые я думаю. Я не реализовал это, так как не думаю, что Google позволяет это в Play Store, по крайней мере, я слышал об этом.
Это всего лишь пример. Вы должны добавить свой собственный сертификат. Если вы добавите поддержку ssh, ошибки _ не будет. Итак, нет исключения IllegalArgumentException
Я решил эту проблему, напишу код, который будет принимать все сертификаты ssl, надеюсь, вы не будете заниматься этим часами, как я. Когда увидел одобренный комментарий, то подумал, что он неразрешим, но решил :)
Код Котлина:
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.io.IOException
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
class ExampleClient {
companion object{
private fun httpClient(accessToken: String): OkHttpClient.Builder? {
return try { // Create a trust manager that does not validate certificate chains
val trustAllCerts =
arrayOf<TrustManager>(
object : X509TrustManager {
@Throws(CertificateException::class)
override fun checkClientTrusted(
chain: Array<X509Certificate>,
authType: String
) {
}
@Throws(CertificateException::class)
override fun checkServerTrusted(
chain: Array<X509Certificate>,
authType: String
) {
}
override fun getAcceptedIssuers(): Array<X509Certificate> {
return arrayOf()
}
}
)
// Install the all-trusting trust manager
val sslContext =
SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, SecureRandom())
// Create an ssl socket factory with our all-trusting manager
val sslSocketFactory = sslContext.socketFactory
val builder = OkHttpClient.Builder()
builder.addInterceptor(object : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val original = chain.request()
// Request customization: add request headers
val requestBuilder = original.newBuilder()
.addHeader("Authorization", accessToken)
val request = requestBuilder.build()
return chain.proceed(request)
}
})
builder.sslSocketFactory(
sslSocketFactory,
(trustAllCerts[0] as X509TrustManager)
)
builder.hostnameVerifier(HostnameVerifier { hostname, session -> true })
builder
} catch (e: Exception) {
throw RuntimeException(e)
}
}
fun getClient(accessToken: String):Retrofit{
return Retrofit.Builder()
.baseUrl("https://sub_domain.base-url.com")
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient(accessToken)!!.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
}
}
}
Код Java:
import android.content.ContextWrapper;
import com.pixplicity.easyprefs.library.Prefs;
import java.io.IOException;
import java.security.cert.CertificateException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class Client {
public static String deviceid;
private static Retrofit retrofit;
public static String BASE_URL = "https://base_url.com/api/";
public static OkHttpClient.Builder getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(new Interceptor() {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
String token;
try {
token = Prefs.getString("token","Token not found");
}catch (Exception e){
token = LoginActivity.getToken();
}
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("deviceid", deviceid).addHeader("Authorization","Bearer " + token);
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
return builder;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Retrofit getClient(String device_id){
deviceid = device_id;
MyLog.log("DEVICE ID : "+deviceid);
if (retrofit == null){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(getUnsafeOkHttpClient().build())
.build();
return retrofit;
}
return retrofit;
}
}
Но разрешено ли это в Play Store? Я думал, что доверительные менеджеры, которые доверяют всем сертификатам, запрещены в Play Store.
Получение того же символа подчеркивания в имени хоста. Есть ли способ обойти то же самое. URL-адрес работает, это запрос почтальона, но почему не в запросе на модернизацию