当 HTTP 请求返回状态为 401 时,如何在 Java 中解析响应正文
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26676405/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to parse the response body in Java, when the HTTP request has return status 401
提问by Ivaylo Slavov
I am consuming a RESTful JSON API using Spring's RestTemplate
and Hymanson. 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:
我正在使用 SpringRestTemplate
和 Hymanson使用 RESTful JSON API 。在某些情况下,我们可能会收到Status 401
带有自定义 JSON 主体的(未授权)响应,该主体由 API 制造商定义,如下所示:
{
"code": 123,
"message": "Reason for the error"
}
We need to parse the body, and use the code
property in our business logic.
我们需要解析正文,并code
在我们的业务逻辑中使用该属性。
This is the error response Java object we need to parse to:
这是我们需要解析为的错误响应 Java 对象:
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 MappingHymansonHttpMessageConverter 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);
}
}
}
The error handler fails with an HttpMessageNotReadableException
in the try block:
错误处理程序失败并HttpMessageNotReadableException
在 try 块中出现:
"Could not read JSON: cannot retry due to server authentication, in streaming mode"
“无法读取 JSON:由于服务器身份验证,无法重试,在流模式下”
This is how I am sending requests:
这是我发送请求的方式:
restTemplate.postForObject(url, pojoInstance, responseClass);
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.
如果使用普通的老式休息客户端程序(如 Postman)执行相同的请求,则会收到预期的 JSON 响应。因此,我认为问题可能在于 Spring 的ClientHttpResponse
实现以某种方式不允许访问响应正文,以防出现 401 状态。
Is it indeed possible to parse the response body?
真的可以解析响应体吗?
Update
更新
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:
根据我的调查,RestTemplate
该类使用ClientHttpResponse
它反过来创建一个sun.net.www.protocol.http.HttpURLConnection
提供输入流的。在那里,输入流被忽略并被IOException
抛出:
cannot retry due to server authentication, in streaming mode
由于服务器身份验证无法重试,在流模式下
So, the HttpURLConnection
's implementation is causing the issue.
因此,HttpURLConnection
的实现导致了这个问题。
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?
有可能避免这个问题吗?也许我们应该使用一种替代实现,在出现错误状态代码时不会忽略响应主体?你能推荐任何替代品吗?
采纳答案by Marios
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 Hymanson's ObjectMapper:
无需自定义处理程序即可尝试以下方法。这个想法是从 HttpStatusCodeException 以字符串形式获取响应,然后您可以将其转换为您的对象。对于转换,我使用了 Hymanson 的 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());