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