해당 포스트는 Spring Cloud에 속한 기술들에 대한 개념과 주요 기술에 대해 알아보고 실무에 적용했었던 내용을 정리하는 포스트입니다.
기본적으로 Spring Cloud Gateway는 클라이언트의 요청을 마이크로서비스로 라우팅하며 이에 대한 응답을 전달합니다. 만약 마이크로서비스에서 예외가 발생하였고 이를 Response로 전달했다면, 게이트웨이는 이 응답을 그대로 전달합니다.
그러나, Spring Cloud Gateway 자체에서 발생한 예외는 다른 Spring MVC / WebFlux 기반 어플리케이션과 마찬가지로 상태 코드 + 에러 페이지를 반환하는데요. 대표적으로 라우팅할 경로를 찾지 못한 경우 발생하는 예외는 404 에러 페이지가 노출됩니다.
따라서 Spring Cloud Gateway에서 발생한 예외를 다른 마이크로서비스에서 전달하는 Response 형식으로 변경하려면 추가적인 설정이 필요합니다.
Spring Cloud Gateway의 전역적인 예외 처리는 ErrorWebExceptionHanlder
를 구현하여 처리합니다.
// Response
@Getter
public class GWErrorResponse {
private String errorMessage;
private LocalDateTime localDateTime;
private Map<String, Object> addtionInfos = new HashMap<>();
public GWErrorResponse(String errorMessage, LocalDateTime localDateTime) {
this.errorMessage = errorMessage;
this.localDateTime = localDateTime;
}
public static GWErrorResponse defaultBuild(String errorMessage) {
return new GWErrorResponse(errorMessage, LocalDateTime.now());
}
}
// ExceptionHandler
@Slf4j
@Order(-1)
@RequiredArgsConstructor
//@Component
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
private final ObjectMapper objectMapper;
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse response = exchange.getResponse();
if (response.isCommitted()) {
return Mono.error(ex);
}
//header
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
if (ex instanceof ResponseStatusException) {
response.setStatusCode(((ResponseStatusException) ex).getStatus());
}
return response
.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory();
try {
GWErrorResponse gwErrorResponse = GWErrorResponse.defaultBuild(ex.getMessage());
byte[] errorResponse = objectMapper.writeValueAsBytes(gwErrorResponse);
return bufferFactory.wrap(errorResponse);
} catch (Exception e) {
log.error("error", e);
return bufferFactory.wrap(new byte[0]);
}
}));
}
}