Retrofit:如何从okhttp拦截器中重试请求?

3

我创建了一个拦截器,有些情况下,我想重试请求'n'次,请问该如何实现?

class NetworkErrorHandler constructor():  Interceptor {

    //Central error handling block for errors which has impact all over the app
    override fun intercept(chain: Interceptor.Chain): Response {
        val request =  chain.request()
        var response = chain.proceed(request) 

        return  
            when (response.code) {
                401 -> { 
                    response
                }
                200 ->{  
                    response
                }
                else -> { 
                        var tryCount = 0
                        while (tryCount < 3) {
                            try { 
                                response = chain.proceed(request)
                                tryCount++
                            }catch (e: java.lang.Exception){
                                tryCount++
                            }
                        }  
                    response
                }
            } 
    }
}

我收到了这个错误:

Suppressed: java.lang.IllegalStateException: network interceptor must call proceed() exactly once

我需要在这里做吗?如果是的话,应该怎么做呢?


我猜我们不能:https://square.github.io/okhttp/4.x/okhttp/okhttp3/-ok-http-client/network-interceptors/ - Ahmad Shahwaiz
4个回答

3

2

这是我的处理方式:

@Slf4j
public class HttpRetryInterceptor implements Interceptor {
    @Override
    public @NotNull Response intercept(Chain chain) throws IOException {
        log.error("Making request for the first time.");
        var request = chain.request();
        Response response = null;
        boolean responseOK = false;
        byte tryCount = 0;
        while (!responseOK && tryCount < 3) {
            try {
                Thread.sleep(5000 * tryCount);
                response = chain.proceed(request);
                log.info("Response is: {}",response);
                log.info("Response message: {}",response.message());
                responseOK = response.isSuccessful();

            }catch (Exception e){
                e.printStackTrace();
                log.error("Request was not successful: {} . Retrying." , tryCount);
            }finally{
                assert response != null;
                response.close();
                tryCount++;
            }
        }

        return response != null ? response : chain.proceed(request);
    }
}

然后我使用类似以下代码将我的拦截器添加到客户端中:new OkHttpClient.Builder().addInterceptor(new HttpRetryInterceptor()).build()


1

所以我能够通过使用这行代码从拦截器中再次进行调用

response.close()      
chain.call().clone().execute()
                

根据问题的完整代码:

//Central error handling block for errors which has impact all over the app
class NetworkErrorHandler constructor(): Interceptor {

        var tryCount = 0
        override fun intercept(chain: Interceptor.Chain): Response {
            val request = chain.request()
            var response = chain.proceed(request)

            return
            when(response.code) {
                401 - > {
                    response
                }
                200 - > {
                    response
                }
                else - > {

                    if (tryCount < 3) {
                        Thread.sleep(2000)
                        tryCount++
                        response.close()
                        chain.call().clone().execute()

                    }
                    response.newBuilder()
                    .code(401) // Whatever code
                    .body("".toResponseBody(null)) // Whatever body
                    .protocol(Protocol.HTTP_2)
                    .message("Network Error")
                    .request(chain.request())
                    .build()
                }
            }
        } 

0

我认为你从这个问题如何使用OkHttp/Retrofit重试HTTP请求?中得到了指引(如果没有,我建议你去看一下)。你代码的问题在于while只受trycount限制,而不是响应结果。尝试在其中添加关于响应状态的验证,以便它不会同时执行两次.proceed方法。

// try the request
Response response = chain.proceed(request);

int tryCount = 0;
while (!response.isSuccessful() && tryCount < 3) {

我能够通过这行代码再次发起请求: response = chain.call().clone().execute() - Ahmad Shahwaiz
除了尝试次数之外,它受响应状态代码的限制。 - Ahmad Shahwaiz
第一条评论中的解决方案是可行的,但如果您可以接受的话,最终将会调用3次服务。 - Sergio Pardo
对于限制,我的意思是针对while本身,而不是在第一次调用和while内部调用之间的限制。我不确定,但我认为编译器会看到没有限制再次执行while,而如果您放置响应,则编译器知道必须等待调用完成后才能继续下一次迭代。 - Sergio Pardo
我现在遇到了这个错误:FATAL EXCEPTION: OkHttp Dispatcher HTTP FAILED: java.lang.IllegalArgumentException: networkResponse.networkResponse != null - Ahmad Shahwaiz
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接