RestTemplate.postForObject()java.net.SocketTimeoutException:读取超时甚至成功

时间:2018-11-21 18:44:46

标签: rest web-services spring-boot socket-timeout-exception

我在同一服务器上有两个Java Spring Boot Web服务应用程序,它们通过REST相互调用。服务A呼叫服务B,服务B成功地根据通知进行操作。 问题是服务A从未收到过服务B的确认,因此认为它已失败,并且根据其循环恢复逻辑,它会再次尝试……并再次尝试……。服务B最终完成了3倍的工作,却没有任何额外的收益。

相关代码(经删除并伪造成保护罪状)如下:

服务A:

public void giveOrderToServiceB(@RequestBody CustomClass message) {
...    
org.springframework.web.client.RestTemplate template = new RestTemplate(clientHttpRequestFactory());
com.mycompany.CustomReply reply = template.postForObject(serviceBUrl, message, CustomReply.class);

服务B REST控制器:

@PostMapping(value="ExecuteTheWork", produces=org.springframework.http.MediaType.APPLICATION_JSON_VALUE, consumes=MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody CustomReply executeTheWork(@RequestBody CustomClass thing) {
    // do something with the thing...
   CustomReply reply = new CustomReply();
    reply.setReply("Successfully executed the work.");
    return reply;
}

在调用RestTemplate.postForObject()之后,服务A捕获的实际异常是

java.net.SocketTimeoutException: Read timed out

请告知。

2 个答案:

答案 0 :(得分:0)

好的,我想我明白了。在该方法完成所有工作之前,我不会从服务B发送回响应,这可能需要几秒钟到几分钟的时间。 如果我立即回答(并跳过处理过程),它将始终如一地工作。 需要将实际工作分拆到单独的线程中。 欢呼声

答案 1 :(得分:0)

在应用程序中注册rest模板的bean时,必须使用超时对其进行配置。以下是Spring应用程序的配置文件

package com.temp.project.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class TempProjectConfig {

    /**
     * Set Timeout for HTTP requests
     * @return
     */
    @Bean
    public ClientHttpRequestFactory getClientHttpRequestFactory() {
        int timeout = 1200000; // here is the timeout property set for rest template
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
                = new HttpComponentsClientHttpRequestFactory();
        clientHttpRequestFactory.setConnectTimeout(timeout);
        return clientHttpRequestFactory;
    }

    /**
     * RestTemplate to call REST endpoints
     * @param clientHttpRequestFactory
     * @return
     */
    @Bean
    public RestTemplate getRestTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
        return new RestTemplate(clientHttpRequestFactory);
    }

}