以下是与设置相关的内容。connectTimeout
案例 - 未知主机
如果您有一个无法访问的主机(例如:),那么您将尽快收到。 没有任何超时。使用 解析主机。http://blablablabla/v1/timeout
UnknownHostException
AbstractPlainSocketImpl :: connect() :: !addr.isUnresolved() :: throw UnknownHostException
InetAddress.getByName(<host_name>)
情况 - 未知端口
如果您有一个可访问的主机,但无法完成连接,那么您会收到 - 尽快。这似乎发生在从 调用 的本机方法中。不考虑超时。ConnectException
Connection refused: connect
DualStackPlainSocketImpl :: static native void waitForConnect(int fd, int timeout) throws IOException
DualStackPlainSocketImpl :: socketConnect()
代理?如果使用代理,情况可能会发生变化。具有可访问的代理可能会遇到超时。
相关问题检查此答案,因为与您遇到的案例有关。
将同一域映射到多个 IP 地址的 DNS 轮循机制将导致客户端连接到每个 IP,直到找到一个 IP。因此,将为列表中不起作用的每个IP添加自己的惩罚。阅读本文了解更多信息。connectTimeout()
结论 如果要获取,则可能需要实现自己的重试逻辑或使用代理。connectTimeout
测试 connectTimeout
您可以参考此答案,了解具有阻止套接字连接完成的终结点从而获取超时的各种方法。选择解决方案时,您可以在 spring-boot 中创建集成测试,以验证您的实现。这可以类似于用于测试 的下一个测试,只是在这种情况下,可以将 URL 更改为阻止套接字连接的 URL。readTimeout
测试读超时
为了测试首先需要有一个连接,因此服务需要启动。然后,可以提供一个终结点,对于每个请求,该终结点返回具有较大延迟的响应。readTimeout
为了创建集成测试,可以在 Spring-boot 中执行以下操作:
1. 创建测试
@RunWith(SpringRunner.class)
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { RestTemplateTimeoutConfig.class, RestTemplateTimeoutApplication.class }
)
public class RestTemplateTimeoutTests {
@Autowired
private RestOperations restTemplate;
@LocalServerPort
private int port;
@Test
public void resttemplate_when_path_exists_and_the_request_takes_too_long_throws_exception() {
System.out.format("%s - %s\n", Thread.currentThread().getName(), Thread.currentThread().getId());
Throwable throwable = catchThrowable(() ->
restTemplate.getForEntity(String.format("http://localhost:%d/v1/timeout", port), String.class));
assertThat(throwable).isInstanceOf(ResourceAccessException.class);
assertThat(throwable).hasCauseInstanceOf(SocketTimeoutException.class);
}
}
2. 配置 RestTemplate
@Configuration
public class RestTemplateTimeoutConfig {
private final int TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(getRequestFactory());
}
private ClientHttpRequestFactory getRequestFactory() {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(TIMEOUT);
factory.setConnectTimeout(TIMEOUT);
factory.setConnectionRequestTimeout(TIMEOUT);
return factory;
}
}
3. 测试开始时将运行的弹簧启动应用程序
@SpringBootApplication
@Controller
@RequestMapping("/v1/timeout")
public class RestTemplateTimeoutApplication {
public static void main(String[] args) {
SpringApplication.run(RestTemplateTimeoutApplication.class, args);
}
@GetMapping()
public @ResponseStatus(HttpStatus.NO_CONTENT) void getDelayedResponse() throws InterruptedException {
System.out.format("Controller thread = %s - %s\n", Thread.currentThread().getName(), Thread.currentThread().getId());
Thread.sleep(20000);
}
}
配置 RestTemplate 的替代方法
配置现有 RestTemplate
@Configuration
public class RestTemplateTimeoutConfig {
private final int TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
// consider that this is the existing RestTemplate
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
// this will change the RestTemplate settings and create another bean
@Bean
@Primary
public RestTemplate newRestTemplate(RestTemplate restTemplate) {
SimpleClientHttpRequestFactory factory =
(SimpleClientHttpRequestFactory) restTemplate.getRequestFactory();
factory.setReadTimeout(TIMEOUT);
factory.setConnectTimeout(TIMEOUT);
return restTemplate;
}
}
使用 RequestConfig 配置新的 RestTemplate
@Configuration
public class RestTemplateTimeoutConfig {
private final int TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(getRequestFactoryAdvanced());
}
private ClientHttpRequestFactory getRequestFactoryAdvanced() {
RequestConfig config = RequestConfig.custom()
.setSocketTimeout(TIMEOUT)
.setConnectTimeout(TIMEOUT)
.setConnectionRequestTimeout(TIMEOUT)
.build();
CloseableHttpClient client = HttpClientBuilder
.create()
.setDefaultRequestConfig(config)
.build();
return new HttpComponentsClientHttpRequestFactory(client);
}
}
为什么不用 来模拟使用 ,来代替请求工厂。因此,将替换任何设置。因此,使用真实应用进行超时测试可能是这里唯一的选择。MockRestServiceServer
RestTemplate
RestTemplate
注意:另请查看这篇关于配置的文章,其中还包括超时配置。RestTemplate