识别改造2请求

时间:2016-06-23 09:05:42

标签: java retrofit okhttp retrofit2 okhttp3

有时请求失败,如果不是由于客户端错误(即:不是4xx),那么我想重试发送相同的请求。
我的所有请求都有一个请求ID标头,当我再次发送某个请求(重试)时,我需要发送与第一个使用的id相同的id。

这听起来很简单,但事实证明使用Retrofit 2很难完成,除非我当然错过了什么。

我的所有请求都是异步的,所以在回调中,如果我需要重试我这样做:

public void onResponse(final Call<T> call, final Response<T> response) {
    if (response.isSuccessful()) {
        handleResponse(response);
    } else if (response.code() >= 400 && response.code() < 500) {
        handleClientError(response);
    } else {
        call.clone().enqueue(this);
    }
}

我还有一个拦截器,用于为所有请求添加标头:

new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        final Request request = chain.request();

        final Request.Builder newRequestBuilder = request.newBuilder()
                .addHeader("Header1-name", "Header1-value")
                .addHeader("Header2-name", "Header2-value")
                ...
                .addHeader("HeaderN-name", "HeaderN-value");

        if (request.header("REQUEST-ID") == null) {
            newRequestBuilder.addHeader("REQUEST-ID", UUID.randomUUID().toString());
        }

        return chain.proceed(newRequestBuilder.build());
    }
};

我认为,因为我克隆了Call,然后(重试)请求将包含前一个请求的标题,但情况并非如此(可能是因为{{1}克隆而不是Call)。

我的问题是我无法识别请求或致电我的Request,因此我无法维护请求/致电ID的地图。
还没有办法向呼叫/请求添加信息(因为它们不是由我生成的,而且缺少和设置这样的情况)。

我想也许我可以使用Interceptor.intercept方法,但是我再也无法控制在那里分配的对象实例,并且请求之间的对象不同。
如果我们已经讨论过这个问题,那么这个标签到底是什么?我无法找到有关它的文档。

知道我怎么能以某种方式解决这个问题? 感谢

1 个答案:

答案 0 :(得分:0)

我采用了另一种方法,而不是使用网络拦截器和回调,我编写了一个使用网络拦截器的解决方案:

class BackoffRetryInteceptor implements Interceptor {
    private static final long RETRY_INITIAL_DELAY = 500;
    private static final long RETRY_MAX_DELAY = 35000;

    @Override
    public Response intercept(final Chain chain) throws IOException {
        Request request = chain.request();

        final Headers.Builder headersBuilder = new Headers.Builder();
        addHeaders(headersBuilder);

        final Headers headers = headersBuilder.build();
        long delay = RETRY_INITIAL_DELAY;
        Response response = null;
        IOException exception = null;

        while (delay < RETRY_MAX_DELAY) {
            exception = null;
            request = request.newBuilder().headers(headers).build();

            try {
                response = chain.proceed(request);

                if (response.isSuccessful() || response.code() != 500) {
                    return response;
                }
            } catch (IOException e) {
                exception = e;
            }

            try {
                Thread.sleep(delay);
                delay *= 2;
            } catch (InterruptedException e) {
                delay = RETRY_MAX_DELAY;
            }
        }

        if (exception != null) {
            throw exception;
        }

        return response;
    }

    private static void addHeaders(final Headers.Builder headers) {
        headers.add("Header1-name", "Header1-value")
                .add("Header2-name", "Header2-value")
                ...
                .add("HeaderN-name", "HeaderN-value")
                .add("Request-Id", UUID.randomUUID().toString());
    }
}

这似乎在我的测试中运作良好 但主要的问题是阻塞了网络线程。

如果有人能想出更好的解决方案,我很乐意听到它。