android - 未应用使用注释的改造拦截器的 OkHttp 调用超时
问题描述
我正在尝试使用 OkHttp 3.12.0 中最近添加的功能:完全操作超时。为此,我还依赖于Invocation
改造 2.5.0 中的新类,它允许我检索方法注释。
注释是:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Timeout {
int value();
TimeUnit unit();
}
改造界面为:
public interface AgentApi {
@Timeout(value = 100, unit = TimeUnit.MILLISECONDS)
@GET("something")
Call<String> getSomething();
}
拦截器是:
class TimeoutInterceptor implements Interceptor {
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request();
final Invocation tag = request.tag(Invocation.class);
final Method method = tag != null ? tag.method() : null;
final Timeout timeout = method != null ? method.getAnnotation(Timeout.class) : null;
if (timeout != null) {
chain.call().timeout().timeout(timeout.value(), timeout.unit());
}
return chain.proceed(request);
}
}
我已经.addInterceptor(...)
在提供给 Retrofit Builder 的 OkHttpClient 中正确添加了 TimeoutInterceptor。
不幸的是,它并没有像我预期的那样工作。达到超时时呼叫不会失败?
虽然在使用拦截器中的链方法时它工作正常:
chain
.withConnectTimeout(connect, unit)
.withReadTimeout(read, unit)
.withWriteTimeout(write, unit)
这是因为必须在呼叫入队之前设置呼叫超时吗?(并且拦截器在这个过程中被触发得太晚了?),或者这是别的什么?
解决方案
不幸的是,你是对的。这是因为OkHttpClient
在执行拦截器链之前获得超时。如果您查看okhttp3.RealCallResponse execute()
类中的方法,您会发现调度超时的行,并且在执行拦截器之前调用它。timeout.enter()
OkHttp
getResponseWithInterceptorChain()
幸运的是,您可以为此编写解决方法 :) 放入您TimeoutInterceptor
的okhttp3
包中(您可以在您的应用程序中创建该包)。这将允许您访问RealCall
具有包可见性的对象。你的TimeoutInterceptor
班级应该是这样的:
package okhttp3;
public class TimeoutInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Invocation tag = request.tag(Invocation.class);
Method method = tag != null ? tag.method() : null;
Timeout timeout = method != null ? method.getAnnotation(Timeout.class) : null;
if (timeout != null) {
chain.call().timeout().timeout(timeout.value(), timeout.unit());
RealCall realCall = (RealCall) chain.call();
realCall.timeout.enter();
}
return chain.proceed(request);
}
}
timeout.enter()
解决方法是在更改超时后再次执行。所有的魔法都发生在一行中:
RealCall realCall = (RealCall) chain.call();
realCall.timeout.enter();
祝你好运!
推荐阅读
- python - Python在外部函数调用上定义嵌套函数的参数
- automation - 如何使用 AppleScript 让 Arcobat 自动将 PDF 转换为图像(JPEG)
- sql - 如何使用 SQL 查询从员工的给定反馈中获得最满意的部门
- android - 如何使用已存在的 DISPLAY_NAME 添加新联系人?
- angular - 角度组件中的附加资源参考
- javascript - 更改表单“方法”不起作用,浏览器发出“GET”请求
- java - 当 Spring/Hibernate JPARepository 返回时,Entties 处于什么生命周期状态?
- sql - 从两列sql创建一行
- sql - 优化 PostgreSQL 查询,对函数扫描和嵌套循环进行缓慢和错误的估计
- batch-file - 如何将一行中的两个字符串存储到不同的变量批次