4

In my previous version of my app I used Apache Client and everything worked and still works. But we decided to move to Retrofit because of some performance gain. The problem is that I get "Unable to resolve host "xxxxxx": No address associated with hostname" every time.

I put this inside manifest

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

May there be anything else I forgot?

This is url: https://www.hbapimanager.azure-api.net/Wallet/CheckNumber

P.S. I have been struggling with this for almost a week

Edited: This is my retrofitFactory class:

private static HttpLoggingInterceptor logging = new HttpLoggingInterceptor()
        .setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE);

private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
        .addInterceptor(logging);

private static HttpUrl url = new HttpUrl.Builder()
        .scheme("https")
        .host(Constants.Network.HOST)
        .build();

private static Retrofit.Builder builder =
        new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create());

public static <T> T createRetrofitService(final Class<T> clazz) {
    Retrofit retrofit = builder.client(httpClient.build()).build();
    return retrofit.create(clazz);
}

And this is interface for requests

    @Headers({
        Constants.Network.HEADER_TYPE,
        Constants.Network.HEADER_KEY
})
@POST(Constants.Network.CHECK_NUMBER)
Call<StatusData> postCheckNumber(@Body CheckNumberPoRD checkNumberPoRD);

@Headers({
        Constants.Network.HEADER_TYPE,
        Constants.Network.HEADER_KEY
})
@GET(Constants.Network.CHECK_NUMBER)
Call<CheckNumberGRD> getCheckNumber(
        @Query("PrimaryKey") String primaryKey,
        @Query("RowKey") String rowKey
);

And i get

09-06 16:58:50.958 7229-7283/kz.halykbank.halykewallet D/OkHttp: --> POST https://www.hbapimanager.azure-api.net/Wallet/CheckNumber http/1.1
09-06 16:58:50.959 7229-7283/kz.halykbank.halykewallet D/OkHttp: Content-   Type: application/json
09-06 16:58:50.959 7229-7283/kz.halykbank.halykewallet D/OkHttp: Content-Length: 27
09-06 16:58:50.959 7229-7283/kz.halykbank.halykewallet D/OkHttp: Ocp-Apim-Subscription-Key: xxxxxxxxxxxxxxxxxxxxxxxxx
09-06 16:58:50.959 7229-7283/kz.halykbank.halykewallet D/OkHttp: {"phone":"x(xxx)xxx-xx-xx"}
09-06 16:58:50.959 7229-7283/kz.halykbank.halykewallet D/OkHttp: --> END POST (27-byte body)
09-06 16:58:51.666 7229-7283/kz.halykbank.halykewallet D/OkHttp: <-- HTTP FAILED: java.net.UnknownHostException: Unable to resolve host "www.hbapimanager.azure-api.net": No address associated with hostname
Amir
  • 16,067
  • 10
  • 80
  • 119
Rustam Ibragimov
  • 2,571
  • 7
  • 22
  • 33

3 Answers3

1

My problem was that I was trying to send request to https://www.example.com. However, there wasn't www.example.com in the hosts of the server, but only example.com.

Rustam Ibragimov
  • 2,571
  • 7
  • 22
  • 33
-1
HttpUrl baseUrl = new HttpUrl.Builder()
                .scheme("https")
                .host("www.hbapimanager.azure-api.net")
                .encodedPath("/Wallet/")
                .build();

OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(new AdditionalHttpHeadersInterceptor(headersProvider))
                .addInterceptor(httpLoggingInterceptor)
                .build();

ApiService apiService = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .client(okHttpClient)
                .addConverterFactory(MoshiConverterFactory.create(moshi))
                .build()
                .create(ApiService.class);

ApiService.java

@Headers({
        Constants.Network.HEADER_TYPE,
        Constants.Network.HEADER_KEY
})
@GET(Constants.Network.CHECK_NUMBER)
Call<CheckNumberGRD> getCheckNumber(
        @Query("PrimaryKey") String primaryKey,
        @Query("RowKey") String rowKey
);

Where Constants.Network.CHECK_NUMBER is "CheckNumber" without slashes

But, maybe you have to set custom ssl socket factory, because of https. The simplest way is next:

Create your custom SSL factory class

public class TLSSocketFactory extends SSLSocketFactory {

    private SSLSocketFactory internalSSLSocketFactory;

    public TLSSocketFactory() {
        SSLContext context = null;
        try {
            context = SSLContext.getInstance("TLS");
            context.init(null, null, null);
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            //TODO check it and fix
            throw new RuntimeException(e);
        }
        internalSSLSocketFactory = context.getSocketFactory();
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return internalSSLSocketFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return internalSSLSocketFactory.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
    }

    private Socket enableTLSOnSocket(Socket socket) {
        if (socket != null && (socket instanceof SSLSocket)) {
            ((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1.1", "TLSv1.2"});
        }
        return socket;
    }
}

and your custom X509 trust manager class

public class CustomX509TrustManager implements X509TrustManager {

    @SuppressLint("TrustAllX509TrustManager")
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    @SuppressLint("TrustAllX509TrustManager")
    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

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

and create your http client

OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .sslSocketFactory(new CustomX509TrustManager(), new TLSSocketFactory())
                .addInterceptor(new AdditionalHttpHeadersInterceptor(headersProvider))
                .addInterceptor(httpLoggingInterceptor)
                .build();
Igor Tyulkanov
  • 5,487
  • 2
  • 32
  • 49
  • I already tried this. sslSocketFactory does not help – Rustam Ibragimov Sep 06 '16 at 17:50
  • the host doesn't exist. Checked it here [check-host.net](https://check-host.net/ip-info?host=www.hbapimanager.azure-api.net) and with Postman. Maybe you have custom DNS server or connect to this host with VPN? – Igor Tyulkanov Sep 07 '16 at 07:03
-7

You're most definitely running into the issue that your base URL looks like this:

http://blah.com/v1/blah

And your service looks like

@GET("/blah/blah/blah")

BUT you actually have to make it look like this:

http://blah.com/v1/blah/

And your service needs to look like

@GET("blah/blah/blah")
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428