24

In our app we met with one special case - if our App.specialFlag == true, we need stop any request from our code. And we think, that the best approach in this situation is include special Interceptor which will stop any our requests, something like this:

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

Also, we should note, that we use RxJavaCallAdapterFactory for wrapping responses into Observables.

But we don't see any methods for stopping request in OkHttp Interceptors.

We came up with two ways to solve our issue:

a) Create special ApiService.class for wrapping every request in our API like this:

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

But we think that it is ugly and cumbersome solution.

b) Throw a RuntimeException in Interceptor, then catch it in every place we use our API.

The second solution is also not good, because we need to include a lot of onErrorResumeNext operators in our chains.

May be someone knows, how to handle our situation in more 'clever' way?..

Thanks in advance!

Pavel Strelchenko
  • 536
  • 1
  • 6
  • 19

3 Answers3

39

One thing missing in the accepted answer is that you need to specify the protocol and the message. If you don't specify that you will get an Exception. Looking like this:

if (App.specialFlag) {
    return new Response.Builder()
                       .code(418) // Whatever code
                       .body("".toResponseBody(null)) // Whatever body
                       .protocol(Protocol.HTTP_2)
                       .message("Dummy response")
                       .request(chain.request())
                       .build();
} else {
    return chain.proceed(chain.request());
}
Damia Fuentes
  • 5,308
  • 6
  • 33
  • 65
Bobstring
  • 460
  • 4
  • 11
  • 13
    Seems with latest OkHttp library, also `body` should be defined. So in my case, adding `.body(ResponseBody.create(MediaType.get("text/html; charset=utf-8"), ""))` solved this problem. Thanks for help. – Menion Asamm Jan 29 '19 at 21:38
  • 1
    +1 body required in the newer version. `ResponseBody.create(null, "")` works, no need to create a MediaType object. – mrj Mar 19 '20 at 11:55
  • 1
    can we also stop the response ? – Ahmad Shahwaiz Aug 15 '21 at 10:01
31

One way to prevent request from being executed(before it starts) it to simply do as you tried to, but with an addition of 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());
}

EDIT 26/09/2019 Updated answer with details mentioned by Bobstring

MatBos
  • 2,380
  • 24
  • 34
  • Thanks for your answer! – Pavel Strelchenko Jul 25 '16 at 12:52
  • 14
    It's worth noting that this only works for *application* interceptors - *network* interceptors require that you call `chain.proceed()` exactly once, or throw a runtime exception otherwise. – npace Apr 10 '17 at 13:10
  • @MatBos, any solution for same issue when `content-length:0` kotlin version – binrebin Jul 11 '20 at 19:24
  • @binrebin Do you mean content-length of request or response? – MatBos Jul 13 '20 at 00:32
  • @MatBos content-length of request – binrebin Jul 13 '20 at 19:03
  • @binrebin Sorry for long response time! One thing that is unclear to me is that since it is a request - you should basically know what you are sending. Hence you should be able to not send it - eliminating the need to block it in the first place. – MatBos Jul 30 '20 at 20:13
  • @binrebin I do not have AndroidStudio with me now but based on the documentation within the `application level interceptor` you can call `chain.request().body().contentLength()` which will tell you the length of the body from which you can tell if the request is actually empty. `In my view this is a bad practice` though. You should be able to not send the request at all. – MatBos Jul 30 '20 at 20:25
  • @MatBos, my logic was this. I make copy of a local datamodel and check it against submitting model and nullyfies fields which are same. To couple with existing logic I thought best thing is to stop request at end. But I made another workaround for it. Thanks for your reply. Useful knowlwdge. – binrebin Jul 31 '20 at 13:51
-2
  1. I would suggest to put the control logic script outside of the OkHttp, since it is used for making http request only. How to trigger request and how to handle the response to update the UI, it doesn't need to care about;

  2. If you wanna, you may create a Class inherited from okhttp3.Interceptor, then override the function intercept and put your control logic script inside.

    OkHttpClient client = new OkHttpClient.Builder()
       .connectTimeout(20, TimeUnit.SECONDS)
       .readTimeout(20, TimeUnit.SECONDS)
       .addInterceptor(new Interceptor())
       .build();
    
Da DUAN
  • 522
  • 1
  • 5
  • 8
  • 1
    That doesn't help. The problem happens exactly when you override `intercept`, because you need to return a Reponse. Therefore, when timing out, you usually throw an Exception, which in the end causes the app to crash. That's why the solution is the one posted by @Bobstring. – mrj Mar 19 '20 at 11:54