java - 识别 Retrofit 2 请求

标签 java retrofit retrofit2 okhttp

有时请求会失败,如果不是由于客户端错误(即:不是 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);
    }
}

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

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 中的请求或调用,因此我无法维护对 id 的请求/调用的映射。
也无法向调用/请求添加信息(因为它们不是由我生成的,并且在这种情况下缺少 setter )。

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

知道如何才能实现这一目标吗? 谢谢

最佳答案

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

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

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

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

关于java - 识别 Retrofit 2 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37987010/

相关文章:

java - 在android java中合并两个图像

java - 从下拉列表中选择一种颜色并将该颜色存储在 cookie 中。

android - 收到改造的不完整响应

android - 设置内容传输编码 : 8bit for Multipart upload with Retrofit

kotlin - 使用 Retrofit 向已经有问号的 URL 添加查询

android - 如何在 Android 的改造响应中添加多个 header

java - 当线程被中断时,BlockingQueue 方法是否总是抛出 InterruptedException?

android - 防止 OkHttp/Retrofit 绕过代理

android - 改造 : Getting error ** End of input at line 1 column 1**

java - 如何将表单数据获取到 Angular Controller 以及如何将其传递给 servlet?