对于 Android/Kotlin,如何仅停止来自 .addNetworkInterceptor 的 Retrofit OkHttp 请求并返回 onSuccess / Failure?

发布于 2025-01-12 01:55:36 字数 2577 浏览 2 评论 0原文

流程:当Retrofit进行API调用时,我想检查互联网连接,如果没有互联网连接,那么我不想继续下去,我的请求应该取消。请非常清楚地注意,我看到了很多与此相关的帖子,但大多数都是在改造完成请求并且进入 onFailure 时进行的,有人正在处理互联网连接检查。我不想那样。我想在一个地方为我的所有 api 调用构建架构,其中我的所有 api 调用将首先检查互联网连接,然后才会继续,否则它将返回,并且应该简单地进入失败状态。

让我用代码解释一下我的问题:

这是我通过 Hilt 提供的 OkHttp 功能:

    ......
okHttpClientBuilder.addNetworkInterceptor(NetworkInterceptor())
            okHttpClientBuilder.addInterceptor(logger)
            okHttpClientBuilder.authenticator(refreshTokenAuthenticator)
            okHttpClientBuilder.addInterceptor(AuthInterceptor(context, tokenProvider))
....

需要注意的是,我将 .addNetworkInterceptor 用于我的 NetworkInterceptor 类,以及其他拦截器,例如 AuthInterceptor,其中我正在附加标头,在那里我使用了 .addInterceptor

NetworkInterceptor

class NetworkInterceptor: Interceptor {
    //TODO: temp hardcoded to test the functionality
    private val isNetworkActive = false

    override fun intercept(chain: Interceptor.Chain): Response {
        val request: Request = chain.request()


        if (isNetworkActive) {
            return chain.proceed(request).newBuilder().build()
        } else {
            chain.call().cancel()
            return chain.proceed(chain.request());
        }
    }
}

所以,基本上它会出现其他条件,如果有任何问题,请更正我的其他条件。人们也从这里抛出异常,但这在我的情况下不起作用,因为事情是,从其他条件进入之后,它将进入 AuthInterceptor 类。我尝试修改上面和下面的序列/语句(例如第一个身份验证,然后是网络身份验证..),但在所有情况下,它都会转到我的 AuthInterceptor。我觉得第一个原因是因为 .addNetworkInterceptor 首先调用,然后 .addInterceptor 即使它是以任何顺序编写的!

这个序列:

okHttpClientBuilder.addNetworkInterceptor(NetworkInterceptor())
        okHttpClientBuilder.addInterceptor(logger)
        okHttpClientBuilder.authenticator(refreshTokenAuthenticator)
        okHttpClientBuilder.addInterceptor(AuthInterceptor(context, tokenProvider)) 

AuthInterceptor

class AuthInterceptor @Inject constructor(private val context: Context, private val tokenProvider: ILocalTokenProvider) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val requestBuilder = chain.request().newBuilder()
        //TODO remove context also from constructor
        requestBuilder.header(AppConstants.INetworkValues.AUTHORIZATION, tokenProvider.getAccessToken() ?: "")
        return chain.proceed(requestBuilder.build())
    }
}

所以,如果你看到我的 return 语句,那么应用程序就会崩溃: java.io.IOException: Canceled

另外我想要的是,如果我从网络拦截器取消我的请求然后我不想进入其他拦截器,它应该返回并且我应该在改造回调中失败。

任何帮助将非常感激,就像我最近几天正在尝试这个基本问题一样。

Flow: I want to check Internet connection when Retrofit makes API call, and if there is no internet connection, then I don't want to proceed further and my request should cancel. Please very clearly note that, I saw many many post related to this, but most of are doing when retrofit is completing the request and it is going in onFailure, there people are handling Internet connection check. I do not want that. I want to make architecture for all my api call in a single place where my all api's call will check Internet connection first then only it will proceed, otherwise it will return and it should go simply in onfailure.

Let me explain my problem with code:

This is my OkHttp functionality which I provide through Hilt:

    ......
okHttpClientBuilder.addNetworkInterceptor(NetworkInterceptor())
            okHttpClientBuilder.addInterceptor(logger)
            okHttpClientBuilder.authenticator(refreshTokenAuthenticator)
            okHttpClientBuilder.addInterceptor(AuthInterceptor(context, tokenProvider))
....

Point to be noted that, I used .addNetworkInterceptor for my NetworkInterceptor class, and for other Interceptors, like AuthInterceptor, where I'm appending headers, there I used .addInterceptor

NetworkInterceptor

class NetworkInterceptor: Interceptor {
    //TODO: temp hardcoded to test the functionality
    private val isNetworkActive = false

    override fun intercept(chain: Interceptor.Chain): Response {
        val request: Request = chain.request()


        if (isNetworkActive) {
            return chain.proceed(request).newBuilder().build()
        } else {
            chain.call().cancel()
            return chain.proceed(chain.request());
        }
    }
}

So, basically it is going to else condition, please correct my else condition if anything is wrong. Also people are throwing an exception from here, but that will not work in my case, because the thing is, after going from else condition, it is going to AuthInterceptor class. I tried to modified sequence / statement of above and down (like first auth and then network one..), but in all cases it is going to my AuthInterceptor. The one reason, I feel is because .addNetworkInterceptor called first and then .addInterceptor even though it is written in any sequence!

this sequence:

okHttpClientBuilder.addNetworkInterceptor(NetworkInterceptor())
        okHttpClientBuilder.addInterceptor(logger)
        okHttpClientBuilder.authenticator(refreshTokenAuthenticator)
        okHttpClientBuilder.addInterceptor(AuthInterceptor(context, tokenProvider)) 

AuthInterceptor

class AuthInterceptor @Inject constructor(private val context: Context, private val tokenProvider: ILocalTokenProvider) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val requestBuilder = chain.request().newBuilder()
        //TODO remove context also from constructor
        requestBuilder.header(AppConstants.INetworkValues.AUTHORIZATION, tokenProvider.getAccessToken() ?: "")
        return chain.proceed(requestBuilder.build())
    }
}

So, if you see my return statement there app is crashing with this: java.io.IOException: Canceled

Also what I want is that if I'm cancelling my req from network intercptor then I don't want to go in other interceptors, it should return and I should get failure in retrofit callback.

Any help would be really appreciated, like I'm trying this basic problem from last few days.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不即不离 2025-01-19 01:55:36

关键部分是检查连接状态应用程序拦截器并在尝试任何连接之前抛出 IOException。网络拦截器必须只执行一次。

请参阅 https://square.github .io/okhttp//features/interceptors/#choosing- Between-application-and-network-interceptors

然后确保在调用者中优雅地处理该异常。

或者当网络不可用时返回虚拟或缓存结果。

正如您已经在做的那样,您需要自己挂钩 ConnectivityManager,

例如 https://github.com/Petrulak/android-kotlin-mvp-clean-architecture/blob/master/app/src/main/java/com/petrulak/cleankotlin/platform/connectivity/ConnectivityChecker.kt

或使用类似https://github.com/erikhuizinga/flomo

The key part is to check the connectivity statusapplication Interceptor and throw an IOException before any connection is attempted. network interceptors must proceed exactly once.

See https://square.github.io/okhttp//features/interceptors/#choosing-between-application-and-network-interceptors

Then make sure you handle that exception gracefully in the caller.

Or return a dummy or cached result when network is not available.

As you are already doing, you need to either hook into the ConnectivityManager yourself,

Something like https://github.com/Petrulak/android-kotlin-mvp-clean-architecture/blob/master/app/src/main/java/com/petrulak/cleankotlin/platform/connectivity/ConnectivityChecker.kt

or use a library like

https://github.com/erikhuizinga/flomo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文