【问题标题】:Why this externa web service call go into error only when the call is performed using Spring RestTemplate?为什么只有在使用 Spring RestTemplate 执行调用时,此外部 Web 服务调用才会出错?
【发布时间】:2017-05-05 14:33:48
【问题描述】:

我正在开发一个 Spring 项目,该项目实现了一个简单的控制台应用程序,该应用程序必须调用一个外部 REST Web 服务,向它传递一个参数并从中获取响应。

对该网络服务的调用是:

http://5.249.148.180:8280/GLIS_Registration/6

其中 6 是指定的 ID。如果您在浏览器中打开此地址(或通过 cURL 工具),您将获得预期的错误消息:

<?xml version="1.0" encoding="UTF-8"?>
<response>
    <sampleid>IRGC 100000</sampleid>
    <genus>Oryza</genus>
    <error>PGRFA sampleid [IRGC 100000], genus [Oryza] already registered for this owner</error>
</response>

此错误消息是此请求的预期响应,我也使用 cURL 工具正确获取它来执行请求。

所以我必须从我的 Spring 应用程序执行这个 GET 请求。

为此,我将这个 getResponse() 方法创建到 RestClient 类中:

@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RestClient {

    RestTemplate restTemplate;
    String uriResourceRegistrationApi;

    public RestClient() {
        super();

        restTemplate = new RestTemplate();
        uriResourceRegistrationApi = "http://5.249.148.180:8280/GLIS_Registration/7";
    }

    public ResponseEntity<String> getResponse() {

        ResponseEntity<String> response = restTemplate.getForEntity(uriResourceRegistrationApi, String.class);
        return response;

    }
}

然后我从这个测试方法中调用这个方法:

@Test
public void singleResourceRestTest() {
    System.out.println("singleResourceRestTest() START");

    ResponseEntity<String> result = restClient.getResponse();

    System.out.println("singleResourceRestTest() END");
}

但是我遇到了一个非常奇怪的行为,发生的事情是:

1)似乎发生了对我的外部 Web 服务的调用(我从 Web 服务日志中看到了它)。

2) Web 服务检索具有值 7 的参数,但似乎无法使用它,而不会出现从浏览器或 shell 语句执行请求的问题:

curl -v http://5.249.148.180:8280/GLIS_Registration/7

但是现在,以这种方式调用,我的 web 服务(我无法发布代码,因为它是 WSO2 ESB 流)给我这个错误消息:

<200 OK,<?xml version="1.0" encoding="UTF-8"?>
<response>
    <error>Location information not correct</error>
    <error>At least one between &lt;genus> and &lt;cropname> is required</error>
    <error>Sample ID is required</error>
    <error>Date is required</error>
    <error>Creation method is required</error>
</response>,{Vary=[Accept-Encoding], Content-Type=[text/html; charset=UTF-8], Date=[Fri, 05 May 2017 14:07:09 GMT], Transfer-Encoding=[chunked], Connection=[keep-alive]}>

查看网络服务日志,使用 RestTemplate 执行调用似乎有一些问题,使用检索到的 ID=7 执行数据库查询。

我知道它看起来非常奇怪,您可以看到:“问题出在您的 Web 服务上,而不是 Spring RestTemplate 上”。这只是部分正确,因为我实现了这个执行低级 Http GET 调用的自定义方法,这个 callWsOldStyle()(放入之前的 RestClient 类):

public void callWsOldStyle() {
    HttpURLConnection connection = null;
    BufferedReader reader = null;

    try {
        URL restAPIUrl = new URL("http://5.249.148.180:8280/GLIS_Registration/7");
        connection = (HttpURLConnection) restAPIUrl.openConnection();
        connection.setRequestMethod("GET");

        // Read the response
        reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        StringBuilder jsonData = new StringBuilder();
        String line;

        while ((line = reader.readLine()) != null) {
            jsonData.append(line);
        }


        System.out.println(jsonData.toString());
    }catch(Exception e) {
        e.printStackTrace();
    }
    finally {
    // Clean up
        IOUtils.closeQuietly(reader);
        if(connection != null)
            connection.disconnect();
    }
}

使用此方法代替 RestTemplate 可以正常工作,这一行:

System.out.println(jsonData.toString());

打印预期结果:

<?xml version="1.0" encoding="UTF-8"?><response><sampleid>IRGC 100005</sampleid><genus>Oryza</genus><error>PGRFA sampleid [IRGC 100005], genus [Oryza] already registered for this owner</error></response>

总结一下:

  • 从浏览器调用我的 WS 就可以了。
  • 使用 cURL 调用我的 WS 可以正常工作。
  • 使用我的 callWsOldStyle() 方法调用我的 WS 可以正常工作。
  • 使用使用 RestTemplate 的方法调用我的 WS,当我的 WS 接收并尝试处理请求时它会出错。

那么,这个问题的原因可能是什么?我错过了什么?也许可以依赖一些错误的标题或类似的东西?

【问题讨论】:

  • RestTemplate 的重点也是允许映射到任何类。由于您似乎正在接收位置,因此请尝试解析为位置而不是字符串。
  • @Lewis_McReu 你到底是什么意思?
  • 目前你有这个:ResponseEntity&lt;String&gt; response = restTemplate.getForEntity(uriResourceRegistrationApi, String.class) 而不是字符串,使用一个类,该类的变量与接收到的 xml 中的变量相对应。
  • 请检查该 API(http://5.249.148.180:8280/GLIS_Registration/6) 的响应状态,它返回 HTTP 500- 内部服务器错误。我认为RestTemplate 只会为 HTTP 2xx 分配响应。如果状态不是 2xx 会抛出异常

标签: spring resttemplate spring-rest


【解决方案1】:

正如皮特所说,您收到内部服务器错误(状态代码 500),因此您应该检查此休息服务的服务器端。

在任何情况下,您都可以为resttemplate 执行以下操作

  • 创建一个org.springframework.web.client.RequestCallback对象,如果 你需要在请求中做一些事情
  • 创建一个org.springframework.web.client.ResponseExtractor&lt;String&gt; 对象以提取您的数据
  • 使用其余模板

org.springframework.web.client.RequestCallback

public class SampleRequestCallBack implements RequestCallback
{

    @Override
    public void doWithRequest(ClientHttpRequest request) throws IOException
    {
    }

}

org.springframework.web.client.ResponseExtractor

public class CustomResponseExtractor implements ResponseExtractor<String>
{
    private static final Logger logger = LoggerFactory.getLogger(CustomResponseExtractor.class.getName()); 
    @Override
    public String extractData(ClientHttpResponse response) throws IOException
    {

        try
        {
            String result = org.apache.commons.io.IOUtils.toString(response.getBody(), Charset.forName("UTF8"));
            if( logger.isInfoEnabled() )
            {
                logger.info("Response received.\nStatus code: {}\n Result: {}",response.getStatusCode().value(), result);
            }
            return result;
        }
        catch (Exception e)
        {
            throw new IOException(e);
        }
    }
}

REST 模板调用

@Test
public void testStack()
{
    try
    {
        String url = "http://5.249.148.180:8280/GLIS_Registration/6";
        String response = restTemplate.execute(url, HttpMethod.GET, new SampleRequestCallBack(), new CustomResponseExtractor());;
        logger.info(response);
    }
    catch (Exception e)
    {
        logger.error("Errore", e);
    }
}

安杰洛

【讨论】:

    猜你喜欢
    • 2019-06-28
    • 2017-07-08
    • 1970-01-01
    • 2020-07-25
    • 2017-08-17
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多