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