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