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

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

问题描述

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

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"
}

我们需要解析正文,并在我们的业务逻辑中使用 code 属性.

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);

如果使用普通的旧式 REST 客户端程序(例如 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天全站免登陆