【问题标题】:Do we have any possibility to stop request in OkHttp Interceptor?我们有可能在 OkHttp 拦截器中停止请求吗?
【发布时间】:2023-03-11 22:11:01
【问题描述】:

在我们的应用程序中,我们遇到了一种特殊情况 - 如果我们的 App.specialFlag == true,我们需要停止来自我们代码的任何请求。我们认为,在这种情况下,最好的方法是包含特殊的Interceptor,它将停止我们的任何请求,如下所示:

if (App.specialFlag) {
    // Somehow stop request
} else {
    return chain.proceed(chain.request());
}

此外,我们应该注意,我们使用 RxJavaCallAdapterFactory 将响应包装到 Observables 中。

但是我们在 OkHttp 拦截器中没有看到任何停止请求的方法。

我们想出了两种方法来解决我们的问题:

a) 创建特殊的 ApiService.class 用于在我们的 API 中包装每个请求,如下所示:

public Observable<User> getUserDetails() {
    if (App.specialFlag) {
        return Observable.just(null);
    }
    return api.getUserDetails();
}

但我们认为它是丑陋和麻烦的解决方案。

b) 在 Interceptor 中抛出一个RuntimeException,然后在我们使用 API 的每个地方捕获它。

第二种方案也不好,因为我们的链中需要包含很多onErrorResumeNext操作符。

可能有人知道,如何以更“聪明”的方式处理我们的情况?..

提前致谢!

【问题讨论】:

    标签: android retrofit rx-java okhttp


    【解决方案1】:

    accepted answer 中缺少的一件事是您需要指定协议和消息。如果你不指定你会得到一个异常。看起来像这样:

    if (App.specialFlag) {
        return new Response.Builder()
                           .code(418) // Whatever code
                           .body(ResponseBody.create(null, "")) // Whatever body
                           .protocol(Protocol.HTTP_2)
                           .message("Dummy response")
                           .request(chain.request())
                           .build();
    } else {
        return chain.proceed(chain.request());
    }
    

    【讨论】:

    • 似乎是最新的 OkHttp 库,还应该定义 body。所以就我而言,添加.body(ResponseBody.create(MediaType.get("text/html; charset=utf-8"), "")) 解决了这个问题。感谢您的帮助。
    • 在较新版本中需要 +1 正文。 ResponseBody.create(null, "") 有效,无需创建 MediaType 对象。
    • 我们也可以停止响应吗?
    【解决方案2】:

    一种防止请求被执行的方法(在它开始之前)它只是按照你的尝试做,但添加了Response.Builder

    if (App.specialFlag) {
        return new Response.Builder()
                           .code(600) //Simply put whatever value you want to designate to aborted request.
                           .protocol(Protocol.HTTP_2)
                           .message("Dummy response")
                           .request(chain.request())
                           .build();
    } else {
        return chain.proceed(chain.request());
    }
    

    2019 年 9 月 26 日编辑 更新了Bobstring提到的详细答案

    【讨论】:

    • 感谢您的回答!
    • 值得注意的是,这仅适用于 application 拦截器 - network 拦截器要求您只调用一次 chain.proceed(),否则会引发运行时异常否则。
    • @MatBos,content-length:0 kotlin 版本时相同问题的任何解决方案
    • @binrebin 您是指请求或响应的内容长度吗?
    • @MatBos 请求的内容长度
    【解决方案3】:
    1. 我建议将控制逻辑脚本放在 OkHttp 之外,因为它仅用于发出 http 请求。如何触发请求,如何处理响应更新UI,无需关心;

    2. 如果你愿意,你可以创建一个继承自okhttp3.Interceptor的Class,然后重写函数intercept并将你的控制逻辑脚本放在里面。

      OkHttpClient client = new OkHttpClient.Builder()
         .connectTimeout(20, TimeUnit.SECONDS)
         .readTimeout(20, TimeUnit.SECONDS)
         .addInterceptor(new Interceptor())
         .build();
      

    【讨论】:

    • 这没有帮助。当您覆盖intercept 时,问题就发生了,因为您需要返回一个响应。因此,在超时的时候,你通常会抛出一个异常,最终导致应用程序崩溃。这就是为什么解决方案是@Bobstring 发布的解决方案。
    猜你喜欢
    • 2014-10-17
    • 2023-01-19
    • 2019-03-03
    • 2016-04-19
    • 2017-08-23
    • 2015-11-18
    • 2021-08-13
    • 1970-01-01
    • 2014-03-27
    相关资源
    最近更新 更多