为JAX-RS 2.0客户端API设置请求超时时间

34

我编写了一个简单的REST Web服务客户端类,它使用JAX-RS 2.0客户端API来进行REST请求。我正在尝试找出如何为每个调用设置请求超时时间。下面是请求的代码:

Client client = ClientBuilder.newBuilder().build();
WebTarget resourceTarget = client.target(restServiceUrl)
        .path("{regsysID}/{appointmentID}/")
        .resolveTemplate("regsysID", regSysId)
        .resolveTemplate("appointmentID", apptId);

Invocation invocation = resourceTarget.request(MediaType.APPLICATION_JSON).buildPut(null);
String createSessionJson = invocation.invoke(String.class);
6个回答

50

注意:这是JAX-RS 2.1上的一种新方法

这是一个非常古老的帖子,但下面的代码将适用于Jersey和Resteasy。

ClientBuilder clientBuilder = ClientBuilder.newBuilder();
clientBuilder.connectTimeout(10, TimeUnit.SECONDS);
clientBuilder.readTimeout(12, TimeUnit.SECONDS);
Client client = clientBuilder.build();

8
没有必要给这个回答点踩。虽然问题是关于2.0版本的,但回答仍然有帮助。在提问时,2.0版本是最新版本。现在2.1版本是最新的,但回答仍然是有关期限内的信息。我会给这个回答点赞。 - Paul Samsotha
1
实际上,这是唯一一个不依赖于特定实现的答案。可能其他作者没有理解API和实现之间的区别。 - Benjamin Marwell

25

您可以通过首先创建一个ClientConfig,并在创建新客户端时将其作为参数提供来实现此目的。

import org.glassfish.jersey.client.ClientProperties;

ClientConfig configuration = new ClientConfig();
configuration.property(ClientProperties.CONNECT_TIMEOUT, 1000);
configuration.property(ClientProperties.READ_TIMEOUT, 1000);
Client client = ClientBuilder.newClient(configuration);

7
我认为你假设我正在使用Jersey作为JAX-RS的实现。实际上,我正在使用Resteasy。但我想找出是否可能使用纯JAX RS 2.0客户端API以通用方式完成。 - sarabdeep singh
1
@Jeroen,你找到了一个纯净的解决方案吗?我需要这个。 - Jdruwe
2
没有通用的 JAX-RS 2.0 方法来做这件事吗? - icordoba
3
请尝试以下内容: client.property(org.apache.cxf.message.Message.CONNECTION_TIMEOUT, 300000) // 5分钟 .property(Message.RECEIVE_TIMEOUT, 300000) // 5分钟 - Custard
感谢@Custard。问题在于我没有将CXF添加到类路径中,因为它只是由Liberty Profile作为JAX-RS 2.0提供程序内部使用。这就是为什么我正在寻找以通用方式进行操作的原因,而不依赖于任何实现类。 - icordoba
2
@Custard的答案非常好。在找到这个线程中的这个小贴士之前,我在许多网站上搜索了解决方案。如果您想保持“通用”,只需使用字符串常量而不是cxf类常量(例如,“javax.xml.ws.client.connectionTimeout”,“javax.xml.ws.client.receiveTimeout”)。 - patrickd

13

通过使用Resteasy,可以按照以下方式构建客户端来实现此目标。

Client client = new ResteasyClientBuilder()
    .establishConnectionTimeout(2, TimeUnit.SECONDS)
    .socketTimeout(2, TimeUnit.SECONDS)
    .build();

我没有看到一个标准配置属性的列表,你可以通过 ClientBuilder.newClient(Configuration configuration) 来设置,这些属性是必需的,以使其具有可移植性。


谢谢@codylerum。是的,我认为在JAX-RS 2.0 ClientBuilder类中指定这些属性的方法会很好。 - sarabdeep singh
4
注意!这仅适用于GET请求。对于其他请求 - Resteasy-> Apache.HttpClient集成存在问题,会丢弃所有客户端配置并替换为默认值。 - Maxim Karavaev
@MaximKaravaev,你有解决问题的方法吗?我也需要发布一篇文章。 - jlanza
@jlanza 我必须向这两个库(HTTPClient和RestEASY)添加依赖项并覆盖一个方法,这导致了这个问题。请参见下一个评论中的代码示例。 - Maxim Karavaev

5

首先,您需要添加相关依赖项(这里是针对WildFly 10.1的):

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-client</artifactId>
    <version>3.0.14.Final</version>
    <scope>provided</scope>
</dependency>

下一步 - 创建一个普通的Apache HttpClient,并将其推入RestEasy Enginge,覆盖一个方法,这会导致问题:
// create here a normal Apache HttpClient with all parameters, that you need
HttpClient httpClient = createHttpClient(connectTimeout,
                                         socketTimeout,
                                         connectionRequestTimeout,
                                         maxTotalHTTPConnections);
// Deprecated Apache classes cleanup https://issues.jboss.org/browse/RESTEASY-1357
// Client Framework not honoring connection timeouts Apache Client 4.3 https://issues.jboss.org/browse/RESTEASY-975
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient) {
        @Override
        protected void loadHttpMethod(ClientInvocation request, HttpRequestBase httpMethod) throws Exception {
            super.loadHttpMethod(request, httpMethod);
            httpMethod.setParams(new BasicHttpParams());
        }
    };

return new ResteasyClientBuilder().httpEngine(engine).build();

请查看 https://issues.jboss.org/browse/RESTEASY-975,似乎问题已在版本3.1.0.Final中得到解决。

你能否澄清一下“已解决”是否意味着现在它可以在POST请求上工作?链接线程中的示例使用GET。 - Markus Barthlen
我可以确认,这个解决方法对于3.1.0.Final和3.0.20.Final是必要的。 - Markus Barthlen
没关系,使用最新版本的httpclient,它可以在没有解决方法的情况下正常工作。 - Markus Barthlen

1

对于那些被困在旧版JAX-RS 2.0 API和旧版Resteasy实现中的人,您可以使用以下方法:

Client client = new ResteasyClientBuilder()             
     .establishConnectionTimeout(3, TimeUnit.SECONDS)
     .socketTimeout(5, TimeUnit.SECONDS).build();

尽管名称为socketTimeout,但根据文档,它代表“等待数据的超时时间”,因此实际上是“读取超时时间”。

0
如果您正在使用Jersey 2.x,则以下是一个简单的解决方案,它对我很有效。
import com.jclient.JClient;

Client c = Client.create();
WebResource webResource = c.resource("requestUrl");
c.setConnectTimeout(yourMins*60*1000);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接