当HTTP请求具有返回状态401时,如何在Java中解析响应主体 [英] How to parse the response body in Java, when the HTTP request has return status 401
问题描述
我正在使用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屋!