Как сохранить сообщение об ошибке, которое возникает во время внутреннего исключения 500 с помощью restTemplate - PullRequest
0 голосов
/ 08 мая 2020

Я хочу знать, как лучше всего сохранять сообщения об ошибках при вызове нескольких связанных микрослужб: у меня есть интерфейс 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, которое отправляется во внешний интерфейс. Если я go и получаю 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 динамически, то есть во время выполнения. Даже не уверен, правильное ли это предприятие или путь к go вниз.

Мое решение, в конце концов, основано на предложении Амита

Я наконец-то создал нестандартный класс, расширяющий пружины 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);
    }

}

Ответы [ 2 ]

1 голос
/ 08 мая 2020

На вашем месте я бы хотел создать совет контроллера для обработки всех видов исключений. Затем я хотел бы создать класс ErrorMessage, который будет иметь настраиваемые поля errorCode, errorMessage в соответствии с требованиями. Исходя из этого совета контроллера, для любых исключений, возникших в приложении, он создаст экземпляр ErrorMessage с такими деталями, как errorCode и errorMessage, и перенесет его в объект ResponseEntity (со статусом HTTP) и вернется к другим микросервисам.

На стороне потребителя проверьте статус ответа и действуйте соответственно.

0 голосов
/ 17 мая 2020

Я думаю, что ответ, который вы ищете, - это создание реализации ExceptionMapper . Интерфейс разработан для обработки java исключений, которые сопоставляются с Response.

В вашем случае, если третья часть выдает исключение, которое обрабатывается реализацией 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
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...