我尝试使用OkHttp 3.12.0中最近添加的一个特性:全操作超时。为此,我还依赖retrofit 2.5.0中新的invocation
类,它允许我检索方法注释。
@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);
}
}
尽管它在使用拦截器中的链方法时工作得很好:
chain
.withConnectTimeout(connect, unit)
.withReadTimeout(read, unit)
.withWriteTimeout(write, unit)
这是因为在呼叫排队之前必须设置呼叫超时吗?(而拦截器在过程中触发得太晚了?),或者这是其他原因?
不幸的是你是对的。这是因为OKHttpClient
在执行拦截器链之前会获得超时。如果您查看OKHTTP3.RealCall类中的response 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();
祝你好运!
我以为这些最新版本应该是兼容的。有一条推文;https://twitter.com/JakeWharton/status/553066921675857922和Retrofit 1.9的更新日志也提到了它。 然而,当我尝试这个: 还是不行。setClient方法抱怨不兼容的客户端对象; 我错过了什么?我还看到OkHttpClient没有实现客户端接口。 我现在使用这种方法;https://medi
问题内容: 我创建了一个RestEASY拦截器,以允许我在Web服务调用完成后在HTTP响应上设置标头值。我的代码看起来像这样… 但是,当我调用服务时,永远不会调用拦截器。我看到webservice调用成功完成,但是拦截器中的任何代码都没有执行过。除了注册拦截器,我还需要做些其他事情吗?是否必须在其他任何地方声明?是否需要包含任何特殊的web.xml参数? 问题答案: 您必须在web.xml的re
问题内容: 我想要一个在中运行的应用程序来进行由代码处理的调用。 理想的方法是仅拦截呼叫(简单,只需使用)并“返回”一些数据。 但是,除了使用调用函数外,我没有找到“返回”对的响应的方法。 这对我来说不起作用,因为该应用程序是我无法控制的嵌入式应用程序。就HTML / javascript应用程序而言,它只是进行调用并接收一些数据。 有什么想法吗? 问题答案: 最后,我还是使用了问题中描述的方法。
问题内容: 我正在使用Java EE 6和Jboss AS7.1,并尝试使用拦截器绑定(来自jboss网站的示例)。 我有一个InterceptorBinding注解: 拦截器: 还有一个豆: 但是拦截器没有被称为。。。 在编写此代码时将调用拦截器: 谢谢你的帮助。 问题答案: 您是否按照参考示例中的说明启用了拦截器? 缺省情况下,bean档案没有通过拦截器绑定绑定的已启用拦截器。必须通过将侦听器
我试图在我的应用程序中配置拦截器,但我无法使其工作。 在我的应用程序配置类中,我以以下方式进行了配置: 拦截器: 有人知道为什么没有被调用吗?