识别 Retrofit 2 请求

Identifying Retrofit 2 requests

有时请求会失败,如果不是由于客户端错误(即:不是 4xx),那么我想重试发送相同的请求。
我所有的请求都有一个请求 ID header,当我再次发送某个请求(重试)时,我需要发送与第一次使用的相同的 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);
    }
}

我还有一个拦截器,用于向所有请求添加 headers:

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,所以(重试)请求将具有前一个请求的 header,但事实并非如此(可能是因为 Call 被克隆而不是 Request).

我的问题是我无法在我的 Interceptor.intercept 中识别请求或调用,所以我无法维护 request/calls 到 id 的映射。
也没有办法向 calls/requests 添加信息(因为它们不是我生成的,并且在这种情况下缺少设置器)。

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

知道如何以某种方式实现它吗? 谢谢

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

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());
    }
}

这在我的测试中似乎很有效。
主要问题是网络线程的阻塞。

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