如何使用 restTemplate 保留在 500 内部异常时抛出的错误信息。

问题描述 投票:0回答:1

我想知道当调用多个链式微服务时,保存错误信息的最佳实践是什么。我有一个Angular前端,它调用一个后端休息服务,而后端休息服务又调用另一个第三方服务。

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

所以为了演示这个问题,让它更容易。

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

@RestController
@RequestMapping("/my-down-stream-service")
public class MyController {

    @RequestMapping(value = "my-method")
    public MyCustomResponse method1() {
       //Some complex logic that catch exceptions and propogates a nice little message
       throw new RuntimeException(“This is my exception that indicates what the response is to my 3rd party service”);
    }
}

在另一个微服务上调用上面的服务,我有一个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
    }
}

enter image description 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代码动态设置消息,也就是在Runtime。但是你不能动态地设置HttpStatus代码的消息,也就是在Runtime。甚至不知道这是否是正确的冒险或道路。

根据Amit的建议,我最终的解决方案是

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

另外在客户端我还得把异常的getBody()JSON投给我的异常。但我不知道它是否是我的异常开始的。所以我还添加了一些HTTP头。在客户端,我检查那个头是否存在,然后我知道body是我的异常,我就可以放心地把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);
    }

}
java spring rest resttemplate http-status-code-500
1个回答
1
投票

如果我是你,我想创建一个控制器建议来处理所有类型的异常。然后,我想创建一个ErrorMessage类,它将根据需求有自定义的errorCode、errorMessage字段。从这个控制器建议,对于应用程序中发生的任何类型的异常,它将创建一个ErrorMessage实例,其中包含错误代码和错误信息等细节,并将其包装成ResponseEntity对象(带有HTTP状态),然后返回给其他微服务。

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


0
投票

我想你要找的答案是创建一个实现的 ExceptionMapper. 该接口被设计用来处理映射到Response的java异常。

在你的例子中,如果第3部分抛出一个异常,而这个异常是由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
    }
© www.soinside.com 2019 - 2024. All rights reserved.