Java 如何使用restTemplate保留500内部异常期间引发的错误消息

Java 如何使用restTemplate保留500内部异常期间引发的错误消息,java,spring,rest,resttemplate,http-status-code-500,Java,Spring,Rest,Resttemplate,Http Status Code 500,我想知道在调用多个链接的微服务时保留错误消息的最佳实践是什么:我有一个角度的前端,它调用一个后端rest服务,该后端rest服务调用另一个rest服务,该服务调用另一个第三方服务 第三方服务有些不可靠。我希望该服务的响应能够传播到我的前端 为了演示这个问题,让它变得更容易 我在下游项目中有一个控制类(单独的微服务/应用程序) 在另一个调用上述服务的微服务上,我有一个restTemplate调用上述服务 public MyResponse doIt() { try {

我想知道在调用多个链接的微服务时保留错误消息的最佳实践是什么:我有一个角度的前端,它调用一个后端rest服务,该后端rest服务调用另一个rest服务,该服务调用另一个第三方服务

第三方服务有些不可靠。我希望该服务的响应能够传播到我的前端

为了演示这个问题,让它变得更容易

我在下游项目中有一个控制类(单独的微服务/应用程序)

在另一个调用上述服务的微服务上,我有一个restTemplate调用上述服务

public MyResponse doIt() {
    try {        
       restTemplate.postForEntity(“MyUrl…”, req, MyResponse.class);
    } catch (final HttpStatusCodeException ex) {
        //If I add a break point and inspect the exception here
    }
}

我可以看到它是一个500内部异常,被发送到前端。 如果我去获取
ex.getResponseBodyAsString()
,我会得到一个包含异常实际细节的JSON映射

{
    "timestamp": "2020-05-06T22:17:08.401+0200",
    "status": 500,
    "error": "Internal Server Error",
    "exception": "java.lang.RuntimeException",
    "message": "This is my exception that indicates what the response is to my 3rd party service",
    "path": "…"
}
我可以把它转换成一个映射,得到消息部分,构造一个新的异常并抛出它

new ObjectMapper().readValue(ex.getResponseBodyAsString(), HashMap.class).get("message")
但在我需要的地方,似乎有很多工作需要实施。 有更好的方法吗

我还尝试创建我自己的HttpStatus,就像一个带有“自定义消息”的550。但是您不能在运行时动态设置HttpStatus代码的消息。甚至不确定这是否是正确的冒险或道路

我的解决方案最终基于Amit的建议

最后,我创建了一个自定义类,该类扩展了springs
ResponseEntityExceptionHandler
。如果这在springboot应用程序的类路径上,它将在从控制器返回异常之前拦截异常。我还创建了自己的异常。原因是如果我想让我的功能触发,我会触发我自己的异常,其他人也可以按照正常的方式。它可以随时更改

在客户端,我还必须将异常的getBody()JSON转换为异常。但我不知道这是否是我的例外。所以我还添加了一些HTTP头。在客户端,我检查该头是否存在,然后我知道主体是我的异常,我可以轻松地将JSON转换为我的异常

@ControllerAdvice
public class MyRestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value = {MyCustomException.class})
    protected ResponseEntity<Object> handleConflict(final MyCustomException ex, final HttpServletResponse response) {      
        if (!response.containsHeader("MYTAG")) {
            response.addHeader("EX_TYPE", "MYTAG");
        }

        //here you can go wild as to what type of or just the normal 500
        //return ResponseEntity.status(ex.getHttpStatus()).body(ex); // 500 internal exception
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex);
    }

}
@ControllerAdvice
公共类MyRestResponseEntityExceptionHandler扩展了ResponseEntityExceptionHandler{
@ExceptionHandler(值={MyCustomException.class})
受保护的ResponseEntity handleConflict(最终MyCustomException ex,最终HttpServletResponse响应){
如果(!response.containsHeader(“MYTAG”)){
addHeader(“EX_类型”、“MYTAG”);
}
//在这里,你可以狂野到什么类型的或只是正常的500
//返回ResponseEntity.status(例如getHttpStatus()).body(例如);//500内部异常
返回ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex);
}
}

如果我是你,我想创建一个控制器建议来处理所有类型的异常。然后,我想创建一个ErrorMessage类,它将根据需要定制errorCode和ErrorMessage字段。根据此控制器建议,对于应用程序中发生的任何类型的异常,它将创建一个带有诸如errorCode和ErrorMessage等详细信息的ErrorMessage实例,并封装到ResponseEntity对象(具有HTTP状态)中,然后返回到其他微服务


在消费者端,检查响应状态并相应地采取行动

我认为您正在寻找的答案是创建的实现。该接口设计用于处理映射到响应的java异常

在您的情况下,如果第三部分抛出由ExceptionMapper实现处理的异常,您可以访问错误消息并在响应中返回该消息

public class ServiceExceptionMapper implements ExceptionMapper<ServiceException>
{
    /**
     * {@inheritDoc}
     */
    @Override
    public Response toResponse(ServiceException exception)
    {
        //grab the message from the exception and return it in the response
    }
公共类ServiceExceptionMapper实现ExceptionMapper
{
/**
*{@inheritardoc}
*/
@凌驾
公共响应(服务异常)
{
//从异常获取消息并在响应中返回
}

谢谢,我根据您的建议添加了随附的解决方案或至少是服务器端部分。
public class ServiceExceptionMapper implements ExceptionMapper<ServiceException>
{
    /**
     * {@inheritDoc}
     */
    @Override
    public Response toResponse(ServiceException exception)
    {
        //grab the message from the exception and return it in the response
    }