Запрос на модернизацию, вызывающий исключение UnknownHostException за VPNAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Запрос на модернизацию, вызывающий исключение UnknownHostException за VPN

Сообщение Anonymous »

Итак, у меня возникла проблема, которая, похоже, возникла прямо из Сумеречной зоны.

Проблема
Мне нужно подключиться к конечной точке REST API из бэкэнда, дело в том, что для доступа к этой конечной точке мне нужно пройти через VPN. В противном случае хост недоступен. На рабочем столе все работает нормально, я открываю Postman, нажимаю конечную точку GET и получаю ответ. Однако, когда я пытаюсь подключиться к той же конечной точке через мое Android-устройство Retrofit, выдается исключение UnknownHostException.

Контекст
URL-адрес конечной точки имеет вид https://api.something.something.net/. Я использую внедрение зависимостей с помощью Dagger, поэтому у меня есть NetworkModule, который выглядит так:

Код: Выделить всё

...
NetworkModule("https://api.something.something.net/")
...
@Module
class NetworkModule(
private val baseHost: String
) {
...
@Provides
@Named("authInterceptor")
fun providesAuthInterceptor(
@Named("authToken") authToken: String
): Interceptor {
return Interceptor { chain ->
var request = chain.request()

request = request.newBuilder()
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Bearer $authToken")
.build()
val response = chain.proceed(request)
}
}
...
@Provides
@Singleton
fun provideOkHttpClient(
curlInterceptor: CurlInterceptor,
@Named("authInterceptor") authInterceptor: Interceptor
): OkHttpClient {
val builder = OkHttpClient.Builder()
builder.addInterceptor(authInterceptor)
builder.addInterceptor(curlInterceptor)
return builder.build()
}
...
@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient, gson: Gson): Retrofit {
return Retrofit.Builder()
.baseUrl(baseHost)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build()
}
}
Затем у меня есть несколько репозиториев, которые выполняют запрос через Retrofit:

Код: Выделить всё

class MyApiRepositoryImpl(
val myRetrofitApi: MyRetrofitApi,
val uiScheduler: Scheduler,
val backgroundScheduler: Scheduler
) : MyApiRepository {

override fun getSomethingFromTheApi(): Observable> {
return myRetrofitApi.getResponseFromEndpoint()
.map {
if (it.isSuccessful) {
DataResource(it.body()?.list!!, ResourceType.NETWORK_SUCCESS)
} else {
throw RuntimeException("Network request failed code ${it.code()}")
}
}
.subscribeOn(backgroundScheduler)
.observeOn(uiScheduler)
.toObservable()
}
}
А это интерфейс API Retrofit:

Код: Выделить всё

interface MyRetrofitApi {

@GET("/v1/something/")
fun getResponseFromEndpoint(): Single
}
Итак, когда я вызываю этот метод репозитория из моего Interactor/UseCases, он проходит прямо через onError и показывает исключение UnknownHostException.

Что я пробовал
  • Я переключил Retrofit на Volley, а затем на Ion, просто чтобы убедитесь, что это не связано с остальным клиентом. У меня во всех случаях одно и то же исключение:

Код: Выделить всё

java.net.UnknownHostException: Unable to resolve host "api.something.something.net": No address associated with hostname

Код: Выделить всё

com.android.volley.NoConnectionError: java.net.UnknownHostException: Unable to resolve host "api.something.something.net": No address associated with hostname
Я попробовал все возможные конфигурации с помощью Retrofit и OkHttpClient:
  • < li>В OkHttpClient я попытался установить для FollowSslRedirects значения true и false. FollowRedirects на true и false. Установите hostnameVerifier, чтобы разрешить прохождение любого имени хоста. Установите SSLSocketFactory, чтобы разрешить прохождение любых неподписанных сертификатов.
  • В моем манифесте я установил для параметра android:networkSecurityConfig значение:< /li>
https://github.com/commonsguy/cwac-netsecurity/issues/5
  • Я тестировал приложение на своем устройстве Android (Android Nougat), на эмуляторах Nougat, Marshmallow и Oreo, а также на эмуляторе Genymotion с Nougat.
    Я попробовал подключиться к случайной общедоступной конечной точке (

    Код: Выделить всё

    https://jsonplaceholder.typicode.com/todos/1
    ), и это сработало отлично. Так что проблема не в подключении к Интернету.
  • В моем манифесте установлены следующие три разрешения:

    Код: Выделить всё

    android.permission.INTERNET
    android.permission.ACCESS_NETWORK_STATE
    android.permission.ACCESS_WIFI_STATE
    
Это очень странно, потому что у меня есть перехватчик, настроенный на преобразование всех запросов в запросы cURL, я скопировал и вставил тот же запрос, который не работает в Postman и работает отлично.
  • На моем ноутбуке я использую Cisco AnyConnect, на моем устройстве Android я При использовании приложения Cisco AnyConnect и AFAIK на эмуляторах и Genymotion он должен использовать ту же сеть, что и хост-компьютер.
Есть пара веб-сайтов, которые видны только через VPN, и я могу видеть их на устройствах и в эмуляторах. Но URL-адрес конечной точки по-прежнему недоступен из приложения.

Пара странных вещей

Да, это становится еще страннее. Если я захожу в конечную точку через браузер Chrome на своем устройстве или в эмуляторе, меня перенаправляют на страницу входа в систему, это потому, что я не отправляю токен авторизации. Теперь, если я проверю ответы сети через chrome://inspect, я смогу получить IP-адрес хоста. Теперь, если я изменю базовый URL-адрес NetworkModule по IP-адресу и добавлю эту строку в перехватчик авторизации:

Код: Выделить всё

@Provides
@Named("authInterceptor")
fun providesAuthInterceptor(
@Named("authToken") authToken: String
): Interceptor {
return Interceptor { chain ->
var request = chain.request()

request = request.newBuilder()
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Bearer $authToken")
.build()
val response = chain.proceed(request)
response.newBuilder().code(HttpURLConnection.HTTP_SEE_OTHER).build() // 

Подробнее здесь: [url]https://stackoverflow.com/questions/53292330/retrofit-request-throwing-unknownhostexception-behind-vpn[/url]
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»