在 Kotlin Android 中使用 Apollo 客户端使用 GraphQL API 时无法执行 HTTP 调用

Posted

技术标签:

【中文标题】在 Kotlin Android 中使用 Apollo 客户端使用 GraphQL API 时无法执行 HTTP 调用【英文标题】:Failed to execute HTTP call in consuming GraphQL API using Apollo Client in Kotlin Android 【发布时间】:2020-01-16 17:36:24 【问题描述】:

我正在使用 Kotlin 开发一个 android 应用程序。我正在尝试在我的应用程序中使用 Apollo Client 来使用 GraphQL API。我安装了 Apollo 客户端并成功生成了模式和类。现在我正在发出一个突变请求,但它没有返回任何响应。

这是我的代码

view.btn_login.setOnClickListener 
            val okHttp = OkHttpClient
                .Builder()
                .addInterceptor( chain ->
                    val original = chain.request()
                    val builder = original.newBuilder().method(original.method(),
                        original.body())
                    chain.proceed(builder.build())
                )
                .build()
            val apolloClient = ApolloClient.builder()
                .serverUrl("https://my-app-name.herokuapp.com/graphql")
                .okHttpClient(okHttp)
                .build()

            val loginMutation = LoginMutation.builder()
                .identity(view.etf_email.text.toString())
                .password(view.etf_password.text.toString())
                .build()

            view.tv_login_error_message.text = "Started making request"
            apolloClient.mutate(loginMutation).enqueue(object: ApolloCall.Callback<LoginMutation.Data>() 
                override fun onFailure(e: ApolloException) 
                    view.tv_login_error_message.text = e.message
                

                override fun onResponse(response: Response<LoginMutation.Data>) 
                    view.tv_login_error_message.text = "Request completed."
                
            )
        

当我点击按钮时,消息只是说“开始提出请求”。响应错误说,他们需要一段时间才能执行 HTTP 调用。我的代码有什么问题,我该如何解决?

以下是我在清单xml中添加的权限。

<uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.CAMERA"/>

这是我在堆栈跟踪中得到的

2019-09-15 22:54:13.027 20508-20580/com.example.memento E/MYAPP: exception
2019-09-15 22:54:13.027 20508-20580/com.example.memento W/System.err: com.apollographql.apollo.exception.ApolloNetworkException: Failed to execute http call
2019-09-15 22:54:13.028 20508-20580/com.example.memento W/System.err:     at com.apollographql.apollo.internal.interceptor.ApolloServerInterceptor$2.onFailure(ApolloServerInterceptor.java:120)
2019-09-15 22:54:13.028 20508-20580/com.example.memento W/System.err:     at okhttp3.RealCall$AsyncCall.execute(RealCall.java:211)
2019-09-15 22:54:13.028 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
2019-09-15 22:54:13.028 20508-20580/com.example.memento W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
2019-09-15 22:54:13.029 20508-20580/com.example.memento W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
2019-09-15 22:54:13.029 20508-20580/com.example.memento W/System.err:     at java.lang.Thread.run(Thread.java:919)
2019-09-15 22:54:13.029 20508-20580/com.example.memento W/System.err: Caused by: java.net.UnknownHostException: Unable to resolve host "memento-nova-api-staging.herokuapp.com": No address associated with hostname
2019-09-15 22:54:13.029 20508-20580/com.example.memento W/System.err:     at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:156)
2019-09-15 22:54:13.029 20508-20580/com.example.memento W/System.err:     at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:103)
2019-09-15 22:54:13.029 20508-20580/com.example.memento W/System.err:     at java.net.InetAddress.getAllByName(InetAddress.java:1152)
2019-09-15 22:54:13.029 20508-20580/com.example.memento W/System.err:     at okhttp3.Dns$1.lookup(Dns.java:40)
2019-09-15 22:54:13.029 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:185)
2019-09-15 22:54:13.029 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.java:149)
2019-09-15 22:54:13.029 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.connection.RouteSelector.next(RouteSelector.java:84)
2019-09-15 22:54:13.029 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:214)
2019-09-15 22:54:13.030 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
2019-09-15 22:54:13.031 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
2019-09-15 22:54:13.031 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
2019-09-15 22:54:13.031 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
2019-09-15 22:54:13.031 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
2019-09-15 22:54:13.031 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
2019-09-15 22:54:13.032 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
2019-09-15 22:54:13.032 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
2019-09-15 22:54:13.032 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
2019-09-15 22:54:13.032 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
2019-09-15 22:54:13.032 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
2019-09-15 22:54:13.033 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
2019-09-15 22:54:13.033 20508-20580/com.example.memento W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
2019-09-15 22:54:13.033 20508-20580/com.example.memento W/System.err:     at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:250)
2019-09-15 22:54:13.033 20508-20580/com.example.memento W/System.err:     at okhttp3.RealCall$AsyncCall.execute(RealCall.java:201)
2019-09-15 22:54:13.033 20508-20580/com.example.memento W/System.err:   ... 4 more
2019-09-15 22:54:13.036 20508-20580/com.example.memento W/System.err: Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
2019-09-15 22:54:13.036 20508-20580/com.example.memento W/System.err:     at libcore.io.Linux.android_getaddrinfo(Native Method)
2019-09-15 22:54:13.036 20508-20580/com.example.memento W/System.err:     at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
2019-09-15 22:54:13.036 20508-20580/com.example.memento W/System.err:     at libcore.io.BlockGuardOs.android_getaddrinfo(BlockGuardOs.java:200)
2019-09-15 22:54:13.036 20508-20580/com.example.memento W/System.err:     at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
2019-09-15 22:54:13.036 20508-20580/com.example.memento W/System.err:     at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:135)
2019-09-15 22:54:13.036 20508-20580/com.example.memento W/System.err:   ... 26 more

【问题讨论】:

您能否提供有关错误消息的更多信息?它是由onFailure 回调方法产生的吗?如果是,则方法中的ApolloException 可能包含有关问题所在的有用信息。您还应该验证(如果可能)您的请求是否已被服务器接收。 这是来自 ApolloException 的错误信息。 我会尝试打印异常的完整堆栈跟踪,以获取有关实际错误的更多详细信息。内部异常通常包含异常的真正原因。 嗨@gmetal,我刚刚更新了添加堆栈跟踪详细信息的问题。 @WaiYanHein 你检查过 Heroku 的日志吗?你的应用在运行吗? 【参考方案1】:

看了你贴的stacktrace后,我相信错误的实际原因是下面这行:

Caused by: java.net.UnknownHostException: Unable to resolve host

您的设备似乎无法通过 DNS 解析服务器 URL。这意味着您的 DNS 服务器可能无法访问,或者您输入了错误的服务器 URL,或者您的设备由于某种原因(例如防火墙)无法访问 DNS 服务器。我会在设备内打开一个浏览器并尝试连接到服务器(只是为了建立连接是可能的)。

【讨论】:

您好,感谢您的回答。是的,我刚刚注意到我的模拟器 wifi 没有显示互联网,因为它由于某种原因无法解析 DNS。我刚刚连接到我的手机热点,它现在正在工作。

以上是关于在 Kotlin Android 中使用 Apollo 客户端使用 GraphQL API 时无法执行 HTTP 调用的主要内容,如果未能解决你的问题,请参考以下文章

Android@Kotlin 在Android studio 中配置Kotlin

使用 Kotlin 在 android 中声明 UI 组件的最佳方法是啥?

如何使用 kotlin 在 android 中初始化小部件

FAQ | 使用 Kotlin 进行 Android 开发

android studio 怎么使用kotlin

在Kotlin中使用注释处理Android框架 kapt