본문 바로가기
Spring

Spring Cloud Gateway CustomGlobalExceptionHandler 구현

by wadekang 2024. 2. 14.

 

기본 응답

Gateway에서 예외가 발생하면 기본으로 응답되는 포맷은 다음과 같음

 

{
  "timestamp": "2024-02-14T08:43:24.955+00:00",
  "path": "/first-service/hello-post",
  "status": 401,
  "error": "Unauthorized",
  "requestId": "3cafcce1"
}

 

응답을 커스텀하거나 예외 발생 시 특별한 처리를 하려고 하는 경우, Gateway 필터를 구현하는 것처럼 ExceptionHandler를 구현할 수 있음

 

GatewayResponseVO

Gateway에서 응답을 커스텀하기 위해 먼저 VO를 정의

 

@Data  
public class GatewayResponseVO {  
  
    private int status;  
    private String message;  
    private Object data;  
    private boolean success;  
  
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")  
    private LocalDateTime timestamp;  
  
    /**  
     * Constructor for success response     
     * @param data  
     */  
    public GatewayResponseVO(Object data) {  
        this.status = 200;  
        this.message = "Success";  
        this.data = data;  
        this.success = true;  
        this.timestamp = LocalDateTime.now();  
    }  
  
    /**  
     * Constructor for error response     
     * @param status  
     * @param message  
     */  
    public GatewayResponseVO(int status, String message) {  
        this.status = status;  
        this.message = message;  
        this.success = false;  
        this.timestamp = LocalDateTime.now();  
    }
}

 

CustomGlobalExceptionHandler 구현

예외가 발생하면 GatewayResponseVO를 정의하여 응답하는 ExceptionHandler

 

@Order(-2) // 우선 순위 부여
@Component // 빈으로 등록하여 ExceptionHandler 작동하도록 함
public class CustomGlobalExceptionHandler extends AbstractErrorWebExceptionHandler {  
  
    public CustomGlobalExceptionHandler(ErrorAttributes errorAttributes, WebProperties webProperties, ApplicationContext applicationContext, ServerCodecConfigurer configurer) {  
        super(errorAttributes, webProperties.getResources(), applicationContext);  
        this.setMessageWriters(configurer.getWriters());  
    }  
  
    @Override  
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {  
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);  
    }  
  
    private Mono<ServerResponse> renderErrorResponse(ServerRequest request) {  
        ErrorAttributeOptions options = ErrorAttributeOptions.of(ErrorAttributeOptions.Include.MESSAGE);
        // errorPropertiesMap을 로그 찍어보면 기본 응답의 형태로 생김 
        Map<String, Object> errorPropertiesMap = getErrorAttributes(request, options);

        // status 있으면 사용, 없으면 500 에러로
        Object status = errorPropertiesMap.getOrDefault("status", 500);  
        GatewayResponseVO response = new GatewayResponseVO((Integer) status, (String) errorPropertiesMap.get("message"));  
  
        return ServerResponse  
                .status((Integer) status)  
                .contentType(MediaType.APPLICATION_JSON)  
                .body(BodyInserters.fromValue(response));  
    }  
}

 

errorPropertiesMap으로 부터 정보를 가져와 GatewayResponseVO를 정의한 후 ServerResponse의 body로 전달

 

{
  "status": 401,
  "message": "Unauthorized",
  "data": null,
  "success": false,
  "timestamp": "2024-02-14T18:03:58"
}

 

ExceptionHandler를 적용한 후 예외를 발생시키면 위와 같이 응답이 바뀐 것을 확인할 수 있음

 

댓글