当HTTP请求具有返回状态401时,如何在Java中解析响应主体 [英] How to parse the response body in Java, when the HTTP request has return status 401

查看:6163
本文介绍了当HTTP请求具有返回状态401时,如何在Java中解析响应主体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Spring的 RestTemplate 和Jackson来使用RESTful JSON API。在某些情况下,我们可能会收到一个由API制造商定义的自定义JSON主体的状态401 (未授权)响应,如下所示:

I am consuming a RESTful JSON API using Spring's RestTemplate and Jackson. In some cases we may receive a Status 401 (Unauthorized) response with a custom JSON body, that is defined by the API manufacturer, and looks like this:

{
    "code": 123,
    "message": "Reason for the error"
}

我们需要解析正文,并使用代码我们的业务逻辑中的属性。

We need to parse the body, and use the code property in our business logic.

这是我们需要解析的错误响应Java对象:

This is the error response Java object we need to parse to:

public class CustomError {

    @JsonProperty
    private Integer code;
    @JsonProperty
    private String message;

    public Integer getCode() {
       return code;
    }
    public String getMessage() {
        return message;
    }
}

以及执行此操作的自定义错误处理程序:

And a custom error handler to do this:

public class CustomErrorHandler extends DefaultResponseErrorHandler {
    private RestTemplate restTemplate;
    private ObjectMapper objectMapper;
    private MappingJacksonHttpMessageConverter messageConverter;


    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        return super.hasError(response);
    }

    @Override
    public void handleError(final ClientHttpResponse response) throws IOException {

        try {
            CustomError error = 
                (CustomError) messageConverter.read(CustomError.class, response);
            throw new CustomErrorIOException(error, error.getMessage());
        } catch (Exception e) {
            // parsing failed, resort to default behavior
            super.handleError(response);
        }
    }
}

错误处理程序失败了try块中的 HttpMessageNotReadableException

The error handler fails with an HttpMessageNotReadableException in the try block:


无法读取JSON:无法重试到期到服务器身份验证,在流模式下

"Could not read JSON: cannot retry due to server authentication, in streaming mode"

这就是我发送请求的方式:

This is how I am sending requests:

restTemplate.postForObject(url, pojoInstance, responseClass);

如果使用普通旧的休息客户端程序(如Postman)执行相同的请求,则预期的JSON响应收到了。因此,我认为问题可能出在Spring的 ClientHttpResponse 实现中,如果处于401状态,某种方式不允许访问响应主体。

If the same request is executed with a plain old rest client program, like Postman, the expected JSON response is received. So, I assume the problem could be with the Spring's ClientHttpResponse implementation somehow not allowing access to the response body, in case of the 401 status.

是否确实可以解析响应主体?

Is it indeed possible to parse the response body?

更新

根据我的调查, RestTemplate 类使用 ClientHttpResponse ,然后创建 sun.net.www.protocol.http.HttpURLConnection 提供输入流。它在那里,输入流被忽略,抛出 IOException

From what I investigated, the RestTemplate class uses ClientHttpResponse which in turn creates an sun.net.www.protocol.http.HttpURLConnection that provides the input stream. It is there, where the input stream is being neglected and an IOException is thrown:


无法在服务器身份验证时重试,在流模式下

cannot retry due to server authentication, in streaming mode

所以, HttpURLConnection 的实施导致了这个问题。

So, the HttpURLConnection's implementation is causing the issue.

是否可以避免这个问题?也许我们应该使用一个替代实现,在发生错误状态代码时不会忽略响应主体?你能推荐任何替代方案吗?

Will it be possible to avoid this problem? Perhaps we should use an alternative implementation that does not ignore the response body in case of an error status code? Can you recommend any alternatives?

推荐答案

尝试以下方法而不需要自定义处理程序。我们的想法是将响应作为HttpStatusCodeException中的字符串获取,然后您可以将其转换为您的对象。对于转换,我使用了Jackson的ObjectMapper:

Try the following approach without needing a custom handler. The idea is to get the response as a string from the HttpStatusCodeException, and then you can convert it to your object. For the conversion I used the Jackson's ObjectMapper:

        try {

            restTemplate.postForObject(url, pojoInstance, responseClass);

        } catch (HttpStatusCodeException e) {

            if (e.getStatusCode() == HttpStatus.UNAUTHORIZED) {

                String responseString = e.getResponseBodyAsString();

                ObjectMapper mapper = new ObjectMapper();

                CustomError result = mapper.readValue(responseString,
                        CustomError.class);
            }
        }

更新:
使用其他工厂也可能有所帮助,因为与您的问题相关的默认错误(请参阅下面的评论):

Update: Usage of a different factory may also help since there is a bug in the default one related to your issue (see comment below):

RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());

这篇关于当HTTP请求具有返回状态401时,如何在Java中解析响应主体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆