【问题标题】:RestTemplate.postForObject Returns Null When ResponseEntity and Http Error Are Returned返回 ResponseEntity 和 Http 错误时 RestTemplate.postForObject 返回 Null
【发布时间】:2019-03-19 21:28:07
【问题描述】:

我调用后端服务来取回 PersonResponse 对象:

PersonResponse response = restTemplate.postForObject(url, request, PersonResponse.class);

PersonResponse 类包含一个“状态”字段,用于指示是否从后端成功检索到一个人的信息:

 public class PersonResponse {
    private String name;
    private String address;
    private ResponseStatus status;
     ......
 }

 public class ResponseStatus {
    private String errorCode;
    private String errorMessage;
     ......
 }

因此,当成功检索到响应时(http 200),我能够返回 PersonResponse 类型的响应。但是,当出现错误(400 或 500)时,后端仍然会返回一个 PersonResponse,但只有“状态”字段填充了错误信息,这就是后端向我返回响应的方式:

 backend code:

 PersonResponse errResp = .....; // set the status field with error info
 return new ResponseEntity<PersonResponse>(errResp, HttpStatus.INTERNAL_SERVER_ERROR); 

但是我在下面的调用返回了一个空响应,尽管它应该给了我一个带有错误信息的 PersonResponse。谁能告诉我这是为什么?

try {
PersonResponse response = restTemplate.postForObject(url, request, PersonResponse.class);
} catch (HttpStatusCodeException se) {
  log.debug(se.getResponseBodyAsString()); 
  // I was able to see the error information stored in PersonResponse in the log
}        
return response;  // always null when 500 error is thrown by the backend

【问题讨论】:

  • 一个方法不能在返回的同时抛出异常。如果它抛出一个异常,那么它不会返回任何东西。返回一个 PersonResponse,包含一个人的所有字段,虽然你根本没有人,只是一个错误,但这种设计真的很糟糕。不要那样做。请注意,您发布的最后一个 sn-p 代码可能无法编译。
  • 感谢您的评论,但我无法控制后端代码。另外,我知道一个方法不能同时返回一些东西并抛出异常,但是当参数之一是 HTTP 状态代码(例如 500)时 ResponseEntity 构造函数如何工作

标签: java spring-boot http httpresponse resttemplate


【解决方案1】:

请阅读以下内容:

默认情况下,RestTemplate 将抛出其中一个exceptions,以防出现HTTP 错误:

HttpClientErrorException

– 在HTTP 状态4xx 的情况下

HttpServerErrorException

 – HTTP 状态 5xx

UnknownHttpStatusCodeException

 – 如果是 unknown HTTP 状态

所有这些exceptions 都是RestClientResponseException 的扩展。

现在,由于您的后端以 5xx(在您的情况下为 500)响应,因此对于您的客户 RestTemplate 它是 HttpServerErrorException

此外,您收到的response 状态为HTTP 500 (INTERNAL SERVER ERROR)RestTemplate 不会使用 POJO 映射/反序列化,因为它不再是成功的 (HTTP 200) 响应,即使后端将错误代码和消息包装在状态中。

因此,在您的情况下,请始终使用null

现在根据您的需要,我从您的原始帖子中推测,即使在 4xx 或 5xx 状态下,您也希望返回 ResponseEntity。您可以为各自的 catch 块实现这一点,例如:

try {
PersonResponse response = restTemplate.postForObject(url, request, PersonResponse.class);
} catch (HttpStatusCodeException se) {
  log.debug(se.getResponseBodyAsString()); 
  // I was able to see the error information stored in PersonResponse in the log
// Here you have to implement to map the error with PersonResponse 
 ResponseStatus  errorStatus = new ResponseStatus();
 errorStatus.setErrorCode(HTTP500);
 errorStatus.setErrorMessage(YOURMESSAGEFROMERROR);
 PersonResponse  responseObject = new PersonResponse();
 responseObject.setResponseStatus(errorStatus);
 return new ResponseEntity<PersonResponse>(responseObject,HTTPStatus.200Or500); // you can design as you need 200 or 500
 } catch (HttpClientErrorException ex){
   //same way for HTTP 4xx 
}

此外,还有其他方法,例如 this :您使用 SpringExceptionHandler 并在 Handler 中集中您决定如果您从后端收到 4xx 或 5xx,如何从客户端响应。 最后,这一切都取决于您如何设计您的系统,因为您说您无法控制后端,那么您必须根据后端响应在您的客户端实施。

希望这会有所帮助。

【讨论】:

  • 您能否详细说明“这种异常处理的方式有很多种”?您是在谈论后端错误处理还是客户端(即我的端)?
  • @jlp :编辑了我在评论中的问题的最后一部分。正如您在 cmets 中已经提到的那样,我只是在谈论客户端:我无法控制后端代码。希望这会有所帮助:)!
【解决方案2】:

您应该处理HttpClientErrorException,并尝试将您的服务返回语句更改为ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errResp)

【讨论】:

    猜你喜欢
    • 2022-08-23
    • 2018-09-15
    • 1970-01-01
    • 1970-01-01
    • 2019-09-08
    • 2020-05-23
    • 2018-03-14
    • 2018-11-19
    • 1970-01-01
    相关资源
    最近更新 更多