我有一个Spring Boot应用程序,正在创建对外部系统的请求。一段时间(3-4分钟)后,外部系统响应。在收到远程API的响应之前,我想保持连接打开状态。我尝试使用webflux,尝试在application.yml文件中为我的应用程序设置连接超时。我可以让应用程序等待响应超过2分钟。我尝试过的一些代码
@Configuration
public class RestConfigurations {
@Bean(name = "restTemplate")
public RestTemplate getRestTemplate(RestTemplateBuilder restTemplateBuilder) {
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
// Error handler
restTemplate.setErrorHandler(new CustomRestTemplateErrorHandler());
// Media converters
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Arrays.asList(
MediaType.APPLICATION_JSON,
MediaType.TEXT_PLAIN,
MediaType.TEXT_HTML));
restTemplate.getMessageConverters().add(converter);
return restTemplate;
}
private ClientHttpRequestFactory getClientHttpRequestFactory() {
int connectionTimeout = 15*60000; // milliseconds
int socketTimeout = 15*60000; // milliseconds
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(connectionTimeout)
.setConnectionRequestTimeout(connectionTimeout)
.setSocketTimeout(socketTimeout)
.build();
CloseableHttpClient client = HttpClientBuilder
.create()
.setDefaultRequestConfig(config)
.setKeepAliveStrategy(connectionKeepAliveStrategy())
.build();
return new HttpComponentsClientHttpRequestFactory(client);
}
public HttpComponentsClientHttpRequestFactory getHttpClientFactory() {
HttpComponentsClientHttpRequestFactory httpClientFactory = new
HttpComponentsClientHttpRequestFactory(
HttpClients.createDefault()
);
httpClientFactory.setConnectTimeout(15 * 600000);
httpClientFactory.setReadTimeout(15 * 600000);
httpClientFactory.setConnectionRequestTimeout(15 * 600000);
return httpClientFactory;
}
public ClientHttpRequestFactory createRequestFactory(){
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(400);
connectionManager.setDefaultMaxPerRoute(200);
RequestConfig requestConfig = RequestConfig
.custom()
.setConnectionRequestTimeout(5000)
.setSocketTimeout(10000)
.build();
CloseableHttpClient httpClient = HttpClients
.custom()
.setConnectionManager(connectionManager)
.setKeepAliveStrategy(connectionKeepAliveStrategy())
.setDefaultRequestConfig(requestConfig)
.build();
return new HttpComponentsClientHttpRequestFactory(httpClient);
}
private ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
return (response,context)-> {
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if ( value != null && param.equalsIgnoreCase("timeout")){
try {
return Long.parseLong(value) * 999999999;
} catch (NumberFormatException exception) {
exception.printStackTrace();
}
}
}
return 15 * 60000;
} ;
}
@Bean(name = "webClient")
public WebClient webClient() {
TcpClient tcpClient = TcpClient
.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000 * 15)//15 minutes
.doOnConnected(connection -> {
connection.addHandlerLast(new ReadTimeoutHandler(15, TimeUnit.MINUTES));
connection.addHandlerLast(new WriteTimeoutHandler(15, TimeUnit.MINUTES));
});
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient).wiretap(true)))
.build();
}
此配置均无效。我尝试像这样使用okhttpclient。
public class OkHttpClientFactoryImpl implements OkHttpClientFactory {
@Override
public OkHttpClient.Builder createBuilder(boolean disableSslValidation) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
ConnectionPool okHttpConnectionPool = new ConnectionPool(50, 30, TimeUnit.SECONDS);
builder.connectionPool(okHttpConnectionPool);
builder.connectTimeout(20, TimeUnit.MINUTES);
builder.readTimeout(20, TimeUnit.MINUTES);
builder.writeTimeout(20, TimeUnit.MINUTES);
builder.retryOnConnectionFailure(false);
return builder;
}
}
@Bean
@Qualifier("OKSpringCommonsRestTemplate")
public ClientHttpRequestFactory createOKCommonsRequestFactory() {
OkHttpClientFactoryImpl httpClientFactory = new OkHttpClientFactoryImpl();
OkHttpClient client = httpClientFactory.createBuilder(false).build();
return new OkHttp3ClientHttpRequestFactory(client);
}
它没有用。除了我已设置的内容外,我不知道什么可能导致连接关闭。
收到答案后,我尝试了:
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofMinutes(10))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpClient client= HttpClient.newHttpClient();
try {
client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
结果是相同的。 2分钟后,我收到一条错误消息,提示java.io.IOException:HTTP / 1.1标头解析器未收到任何字节
答案 0 :(得分:0)
我发现了问题。实际上是由于服务器在呼叫的另一端。 Express服务器默认在2分钟后关闭连接。
答案 1 :(得分:0)
增加服务器/ LB上的客户端空闲超时数量。