【问题标题】:Kotlin coroutines and SecurityExceptionKotlin 协程和 SecurityException
【发布时间】:2019-02-14 07:25:01
【问题描述】:

我正在使用 Retrofit 的协程适配器,我看到,如果网络调用因 URL 不正确而失败,try/catch 块将捕获它,但如果我删除 Internet 权限以便我们得到 SecurityException,则应用程序崩溃了。

这是处理改造响应的代码:

override suspend fun execute(): Result<IpAddress> = try {
    val result = dataRepository.getIpAddress().await()
    Result.Success(result)
} catch (throwable: Throwable) {
    if (throwable is JobCancellationException) {
        throw throwable
    }
    Result.Error(throwable)
}

存储库很简单

override suspend fun getIpAddress(): Deferred<IpAddress> = dataService.getIpAddress()

interface DataService {
    @GET("/?format=json")
    fun getIpAddress(): Deferred<IpAddress>
}

为什么像 UnknownHostException 这样的异常会被捕获,但 SecurityException 会使应用程序崩溃?

这是崩溃日志

09-09 12:27:25.467 12465 12495 E AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
09-09 12:27:25.467 12465 12495 E AndroidRuntime: Process: com.example.coroutines, PID: 12465
09-09 12:27:25.467 12465 12495 E AndroidRuntime: java.lang.SecurityException: Permission denied (missing INTERNET permission?)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:151)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:105)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at java.net.InetAddress.getAllByName(InetAddress.java:1154)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.Dns$1.lookup(Dns.java:40)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:185)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.java:149)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.connection.RouteSelector.next(RouteSelector.java:84)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:214)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:147)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at java.lang.Thread.run(Thread.java:764)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at libcore.io.Linux.android_getaddrinfo(Native Method)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at libcore.io.BlockGuardOs.android_getaddrinfo(BlockGuardOs.java:172)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:137)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    ... 26 more
09-09 12:27:25.467 12465 12495 E AndroidRuntime: Caused by: android.system.ErrnoException: android_getaddrinfo failed: EACCES (Permission denied)
09-09 12:27:25.467 12465 12495 E AndroidRuntime:    ... 29 more

【问题讨论】:

  • 旁白:不要使用Result&lt;IpAddress&gt; 作为suspend fun 的返回类型。只需使用IpAddress
  • Result 是一个密封类,它允许我将 Success 和 Error 包装为 Result 类,以便客户端可以处理调用的结果。
  • 除非您将整个代码库都提交给 FP 习惯用法和高阶函数,否则抛出异常以发出错误信号会更自然。更不用说一次性处理大量错误的麻烦了。

标签: android kotlin retrofit2 kotlinx.coroutines


【解决方案1】:

因为在一种情况下,Retrofit 会在内部捕获它并将其作为错误传递回来,因为您知道您可能希望处理它。在另一种情况下,它不会捕获它并且它会使应用程序崩溃。没有办法改变这种情况,因为它发生在他们的内部线程上,只需要保留互联网权限。

【讨论】:

  • 但是包装 await() 调用的 try/catch 不应该捕获异常吗?
  • 没有。线程 A 上的 try catch 不会捕获线程 B 上发生的异常。
  • 我认为它应该捕获异常,因为 Retrofit 应该传播它。吞咽异常,包括Errors,对任何人都没有好处。
  • 我确实建议向 Retrofit 提交错误。您可以轻松地创建一个完全没有协程的复制器。 Retrofit 应该将所有异常传播到用户代码,将如何处理它们的决定留给用户。
  • @RomanElizarov 这不是错误。这是一个哲学的选择。找不到主机并不是一个例外,它是预期的可能结果。用户可能传入了无效的 url。这是一个使操作无法进行的编程错误。抛出异常是正确的举动。
猜你喜欢
  • 2019-12-25
  • 2019-08-03
  • 2022-08-18
  • 2019-02-19
  • 1970-01-01
  • 1970-01-01
  • 2017-08-18
  • 1970-01-01
相关资源
最近更新 更多