当前位置: 首页 > 知识库问答 >
问题:

Spring Boot RestTemboard ResourceAccessException:POST请求上的I/O错误无法响应

颜鸿云
2023-03-14

我使用Spring Boot,在保持与第三方REST服务的长期连接的同时,遇到了以下问题:

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:5000/products/10": localhost:5000 failed to respond; nested exception is org.apache.http.NoHttpResponseException: localhost:5000 failed to respond
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:732)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:680)
    at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:435)
    at com.example.pipeline.domain.service.nlp.NLPService.getDocumentsInfoNew(NLPService.java:42)
    at com.example.pipeline.domain.batch.steps.NLPTasklet.execute(NLPTasklet.java:170)
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:272)
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81)
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375)
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145)
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200)
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
    at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:394)
    at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:135)
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:308)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:141)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.apache.http.NoHttpResponseException: localhost:5000 failed to respond
    at org.apache.http.impl.conn.DefaultHttpRespons

此服务可以在返回结果之前将连接保持一个小时或更长时间。

我的RestTemplate配置如下所示:

public static RestTemplate createRestTemplate(int connectionTimeoutMs, int readTimeoutMs, ObjectMapper objectMapper) {

        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(HttpClients.createDefault());
        httpRequestFactory.setConnectTimeout(connectionTimeoutMs);
        httpRequestFactory.setReadTimeout(readTimeoutMs);

        RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
        interceptors.add(new LoggingRequestInterceptor());
        restTemplate.setInterceptors(interceptors);
        restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(httpRequestFactory));
        MappingJackson2HttpMessageConverter messageConverter = restTemplate.getMessageConverters().stream().filter(MappingJackson2HttpMessageConverter.class::isInstance)
                .map(MappingJackson2HttpMessageConverter.class::cast).findFirst().orElseThrow(() -> new RuntimeException("MappingJackson2HttpMessageConverter not found"));
        messageConverter.setObjectMapper(objectMapper);

        restTemplate.getMessageConverters().stream().filter(StringHttpMessageConverter.class::isInstance).map(StringHttpMessageConverter.class::cast).forEach(a -> {
            a.setWriteAcceptCharset(false);
            a.setDefaultCharset(StandardCharsets.UTF_8);
        });

        return restTemplate;
    }

}

RestTemplate restTemplate = HttpUtils.createRestTemplate(60 * 1000, 3 * 60 * 60 * 1000, objectMapper);

我能做些什么来修复我这边的问题吗,或者这是http://localhost:5000服务端的纯问题,应该在那里修复?

共有1个答案

庄博厚
2023-03-14

最后,我提出了以下RestTempleat配置:

public class HttpUtils {

    static final Logger LOGGER = LoggerFactory.getLogger(HttpUtils.class);

    private static final int HTTP_CLIENT_RETRY_COUNT = 3;

    private static final int MAXIMUM_TOTAL_CONNECTION = 10;
    private static final int MAXIMUM_CONNECTION_PER_ROUTE = 5;
    private static final int CONNECTION_VALIDATE_AFTER_INACTIVITY_MS = 10 * 1000;

    public static RestTemplate createRestTemplate(int connectionTimeoutMs, int readTimeoutMs, ObjectMapper objectMapper) {

        HttpClientBuilder clientBuilder = HttpClients.custom();

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();

        // Set the maximum number of total open connections.
        connectionManager.setMaxTotal(MAXIMUM_TOTAL_CONNECTION);
        // Set the maximum number of concurrent connections per route, which is 2 by default.
        connectionManager.setDefaultMaxPerRoute(MAXIMUM_CONNECTION_PER_ROUTE);

        connectionManager.setValidateAfterInactivity(CONNECTION_VALIDATE_AFTER_INACTIVITY_MS);

        clientBuilder.setConnectionManager(connectionManager);

        clientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(HTTP_CLIENT_RETRY_COUNT, true, new ArrayList<>()) {

            @Override
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                LOGGER.info("Retry request, execution count: {}, exception: {}", executionCount, exception);
                return super.retryRequest(exception, executionCount, context);
            }

        });

        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(clientBuilder.build());
        httpRequestFactory.setConnectTimeout(connectionTimeoutMs);
        httpRequestFactory.setConnectionRequestTimeout(readTimeoutMs);
        httpRequestFactory.setReadTimeout(readTimeoutMs);

        RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
        interceptors.add(new LoggingRequestInterceptor());
        restTemplate.setInterceptors(interceptors);
        restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(httpRequestFactory));

        MappingJackson2HttpMessageConverter messageConverter = restTemplate.getMessageConverters().stream().filter(MappingJackson2HttpMessageConverter.class::isInstance)
                .map(MappingJackson2HttpMessageConverter.class::cast).findFirst().orElseThrow(() -> new RuntimeException("MappingJackson2HttpMessageConverter not found"));
        messageConverter.setObjectMapper(objectMapper);

        restTemplate.getMessageConverters().stream().filter(StringHttpMessageConverter.class::isInstance).map(StringHttpMessageConverter.class::cast).forEach(a -> {
            a.setWriteAcceptCharset(false);
            a.setDefaultCharset(StandardCharsets.UTF_8);
        });

        return restTemplate;
    }

}

public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingRequestInterceptor.class);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
    traceRequest(request, body);
    ClientHttpResponse response = execution.execute(request, body);
    traceResponse(response);
    return response;
    }

    private void traceRequest(HttpRequest request, byte[] body) throws IOException {
    LOGGER.debug("===========================request begin================================================");
    LOGGER.debug("URI         : {}", request.getURI());
    LOGGER.debug("Method      : {}", request.getMethod());
    LOGGER.debug("Headers     : {}", request.getHeaders());
    LOGGER.debug("Request body: {}", new String(body, "UTF-8"));
    LOGGER.debug("==========================request end================================================");
    }

    private void traceResponse(ClientHttpResponse response) throws IOException {
    StringBuilder inputStringBuilder = new StringBuilder();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"));
    String line = bufferedReader.readLine();
    while (line != null) {
        inputStringBuilder.append(line);
        inputStringBuilder.append('\n');
        line = bufferedReader.readLine();
    }
    LOGGER.debug("============================response begin==========================================");
    LOGGER.debug("Status code  : {}", response.getStatusCode());
    LOGGER.debug("Status text  : {}", response.getStatusText());
    LOGGER.debug("Headers      : {}", response.getHeaders());
    LOGGER.debug("Response body: {}", inputStringBuilder.toString());
    LOGGER.debug("=======================response end=================================================");
    }
}
 类似资料:
  • 当我调用restendpoint(rest模板http客户端)“myservice..com/rest/api/”时,有时会出现以下错误。此错误的原因是什么?这是客户端还是服务器错误?

  • 尝试将数据发布到api时出错。下面是代码片段。期待早日得到帮助!谢谢 7组织。springframework。网状物客户ResourceAccessException:“jirasdtest.myoutotec.com/rest/api/2/issue/SD-1043/comment”的POST请求出现I/O错误:连接超时;嵌套异常为java。网SocketTimeoutException:连接在

  • 我已经用谷歌搜索了它。但是这些都不能解决我的问题。我在调用rest控件时,代码中的SSL证书出现了问题。 我的控制方法是: 错误为:-I/O错误在“https://myurl.com”的POST请求上:sun.security.validator.validatoreXception:PKIX路径构建失败:sun.security.provider.certpath.suncertPathBuil

  • 我正在使用rest模板调用外部系统,它在本地运行正常,没有任何超时设置,但在我的测试服务器上,它给了我以下错误: “的POST请求时出现I/O错误”https://externalsystem/url“:连接被拒绝:连接;嵌套的异常是java。网ConnectException:连接被拒绝:连接

  • 我在我的反应应用程序中有一个axios请求,为此我遵循axios npm文档。 这是我的axios请求 我能够成功记录成功请求的数据。但是,当我故意产生一个错误并尝试将其记录到console.log中时,我不会将结果记录下来,我只是看到了 邮递http://localhost:3000/login 401(未经授权):3000/登录:1 错误:请求失败,状态代码401 login.js:66 在c

  • 我正在使用Spring RestTemplate进行RESTful调用。我还使用自定义ClientHttpRequestInterceptor记录请求和响应,以便进行调试。 为了多次读取响应(一次用于日志记录,一次用于处理),我使用了BufferingClienthtPrequestFactory。以下是设置: 不知道为什么会发生这种情况,但我打开了调试器,并为request.getBody()设