当RestTemplate因无法解析响应而抛出RestClientException时,我该如何从响应中获取数据?

3
使用restTemplate.exchange(uri, method, entity, responseType)进行REST调用时,如果响应的responseType不正确,会导致RestClientException错误。例如:
org.springframework.web.client.RestClientException: Error while extracting response for type [java.util.List<java.lang.Byte>] and content type [application/json;charset=UTF-8];
nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Numeric value (281759) out of range of Java byte

由于这不是一个RestClientResponseException,我们似乎没有访问响应数据(如状态码和正文,甚至不是它们的原始形式)的权限。
是否有方法可以从原始(无法解析的)响应中获取(原始)数据?(用于日志记录)

你好,你尝试过在Spring文档中提到的getRawStatusCode()getResponseBodyAsString()了吗?链接在这里:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestClientResponseException.html#getRawStatusCode-- - Vivek
这些是 RestClientResponseException 的方法,但它们在 RestClientException 中不可用。 - neXus
好的,刚刚看到了,既然这不是一个“RestClientResponseException”。 所以你正在寻找来自上游服务器的原始响应(至少),尽管由于某些原因(包括你提到的原因)restTemplate无法解析。 - Vivek
3个回答

0
尝试在RestTemplate的messageConverters中添加StringHttpMessageConverter。
StringHttpMessageConverter stringHttpMessageConverter
            = new StringHttpMessageConverter(StandardCharsets.UTF_8);
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter
            = new MappingJackson2HttpMessageConverter(objectMapper);

RestTemplate restTemplate = new RestTemplate(factory);
restTemplate.setMessageConverters(
            List.of(stringHttpMessageConverter, jackson2HttpMessageConverter));

0

尝试将响应解析为String。参见此答案-类似的概念可以与exchange方法一起使用。

编辑:如果异常并不总是发生,而您仍希望能够轻松地映射正确的响应,则可以覆盖相应的 MessageConverter(实际上是抛出异常),然后在之后执行任何操作,因为转换器会为您提供原始的HttpInputMessage

假设您正在使用MappingJackson2HttpMessageConverter,它应该看起来像这样(尚未测试)

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
    return new MappingJackson2HttpMessageConverter(objectMapper) {
        @Override
        public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
            try {
                return super.read(type, contextClass, inputMessage);
            } catch (HttpMessageNotReadableException e) {
                // LOG here...
                throw e;
            }
        }
    };
}

但是那么我必须自己进行解析并将其转换为所需类型的对象?Spring提供该功能吗? - neXus
当然,但是您要求的是原始响应。这不是您想要的吗? - stuchl4n3k
如果出现问题,原始(字符串)数据就可以了,因为(在我的情况下)它只是用于记录日志。但在正常情况下,我希望得到已输入的响应主体。 - neXus
这意味着,如果我想在异常情况下获取信息,我应该始终将响应读取为字符串,并尝试将其自己解析为预期的响应类型。这样,如果出现解析异常,则可以使用字符串信息。但这也意味着我必须自己进行解析。 - neXus
这看起来是一个不错的选择。在inputMessage的主体中,有一个InputStream,因此我必须将其缓存,以便在出现问题时可以再读取一次。但是我在这里可以访问到我所需要的一切,而不必调用端点两次,仍然可以使用现有的解析功能。 - neXus

-1
 final RestTemplate restTemplate = new RestTemplate();
        try { 
            restTemplate.exchange(uri, method, entity, responseType);
        } catch (RestClientException e) {
            //for logging exact message
            restTemplate.getForObject("https://httpbin.org/ip", String.class); 

        }

这只是两次进行相同调用操作。开销很大。 - neXus
由于在失败的情况下需要再次调用它。 - manoj mallick
但是原因是什么呢?我认为信息已经被检索到了,所以它已经在客户端了。记录一个与实际导致错误不同的响应是很奇怪的。连续调用返回相同的信息并不总是正确的。 - neXus
由于我们不知道实际的响应类型,因此在接收/上述后手动映射响应有两个选项。 - manoj mallick
这就是你的解决方案所允许的,但这并不是你的解决方案必要的原因。我不想重复进行相同的网络调用。 - neXus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接