[Spring cloud] spring cloud gateway 활용

WOOK JONG KIM·2022년 12월 12일
0

패캠_java&Spring

목록 보기
102/103
post-thumbnail

Spring Cloud Gateway

Spring Cloud Gateway는 스프링 부트와 스프링 클라우드를 사용하여 빌드한 서비스로 마이크로서비스 아키텍처에서 서비스 간의 통신을 담당하는 역할
-> 로드 밸런싱, 인증, 보안 등의 기능을 제공하여 사용자가 쉽게 마이크로서비스 아키텍처를 구축할 수 있도록 지원

클라이언트들이 각각 api들의 주소를 찾아 연동할려면 어렵다
-> 하나의 단일 진입점을 제공(API 통합)
-> 이를 지원하는 것이 Spring Cloud Gateway, zuul

구조:
client -> Gateway handler mapping -> Gateway Web handler -> Filter chain -> Destination

client가 요청을 보내면 그 요청을 매핑해주는 Gateway handler mapping이 있고, 매핑 된 이후 그 요청을 처리해주는 것이 Gateway Web handler

Filter chain에서 요청들의 전,후 처리

Gateway Handler Mapping은 이 API Gateway에서 요청이 어떤 라우팅( 요청을 전달할 대상을 결정하는 기능) 룰에 따라 처리될지를 정의하는 기능
-> 즉, Gateway Handler Mapping을 사용하면 API Gateway가 어떤 요청을 어떤 라우팅 룰에 매핑하여 처리할지를 설정

Gateway Web Handler는 Spring Cloud Gateway API Gateway에서 요청을 처리하기 위해 사용하는 컴포넌트
-> Gateway Web Handler는 요청을 받아 적절한 라우팅 룰에 매핑하여 처리하고, 요청에 대한 응답을 만들어 내는 역할
-> 라우팅 룰은 Gateway Handler Mapping을 통해 설정되며, Gateway Web Handler는 이 라우팅 룰을 사용하여 요청을 적절히 처리


Api GateWay를 활용한 api proxy 실습

api gateway를 통해 요청이 전달 되도록

api gw(localhost:7080, spring cloud) -> photoApp(localhost:8080)

photo App 컨트롤러 들(8080)

@Slf4j
@RestController
public class HeadController {
    @GetMapping("/v1.0/headservice")
    public ResponseEntity retrieveHeadData(@RequestHeader(value = "X-PHOTO-API-VERSION") String apiVersion) {
        LOG.info("header data: {}", apiVersion);
        return ResponseEntity.ok("ok");
    }
}
@RestController
public class NewServiceController {
    @GetMapping("/v1.0/newservice")
    public String releaseNewService() {
        return "open new service";
    }
}
@RestController
public class PostReadController {
    @GetMapping("/v1.0/contents/1")
    public ResponseEntity<?> retriveInMemoryData() {
        Content content = Content.builder()
                .contentId(UUID.randomUUID().toString())
                .body("get data")
                .title("sp gateway test")
                .writerNickName("testnick")
                .build();

        return ResponseEntity.ok(content);
    }
}

api gw

application.yml

server.port: 7080
spring.application:
  name: api-gw

spring.config.import: api-gw.yml #,eureka-client.yml

api-gw.yml

spring.cloud:
  gateway:
    httpclient:
      connect-timeout: 3000
      response-timeout: 10s
    routes:
      - id: post-service
        #dest
        uri: http://localhost:8080
        predicates: ## 세부 조건 설정(7080포트로 요청 보내도 처리됨)
          - Path=/v1.0/contents/**
      - id: time-service # 지정된 시간 이후(After)에만 접근 가능하도록 ## 시간 전에 접속하면 404
        uri: http://localhost:8080
        predicates:
          - Path=/v1.0/newservice
          - After=2021-03-21T23:35:01.126+09:00[Asia/Seoul]
      - id: header-service # Header 매핑(요청 헤더가 같은 경우에만 통과)
        ## server to server , 요청 server -> api gw -> headerservice
        uri: http://localhost:8080
        predicates:
          - Path=/v1.0/headservice
          - Header=X-PHOTO-API-VERSION, 1.0.0 # 헤더가 다르면 404 not found


API GW를 이용한 API 공통에러 처리

webMVC(white page)와 webFlux(json)의 error 처리 방식에는 차이가 있음
-> 밑의 코드는 webFlux 기반의 spring cloud gateway에서 에러처리 구현 방법

@Slf4j
@Order(-1)
@RequiredArgsConstructor
//@Component
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
    private final ObjectMapper objectMapper; // json 응답을 주기 위해(white page X)

    @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]);
                    }
                }));
    }
}
@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());
    }

}
profile
Journey for Backend Developer

0개의 댓글