Spring Cloud Gateway - Filter
[FilterConfig]
- 이전에 application.yml에 설정하였던 정보를 아래와 같이 Java로 설정할 수 있다.
@Configuration
public class FilterConfig {
@Bean
public RouteLocator gatewayRoutes(RouteLocatorBuilder builder, AuthorizationHeaderFilter myfilter) {
return builder.routes()
.route(r -> r.path("/first-service/**")
.filters(f -> f.addRequestHeader("first-request", "first-request-header-by-java")
.addResponseHeader("first-response", "first-response-header-by-java")
.filter(myfilter.apply(new AuthorizationHeaderFilter . Config ()))
)
.uri("http://localhost:8081"))
.route(r -> r.path("/second-service/**")
.filters(f -> f.addRequestHeader("second-request", "second-request-header-by-java")
.addResponseHeader("second-response", "second-response-header-by-java"))
.uri("http://localhost:8082"))
.build();
}
}
- Request : Gateway Client -> Gateway Handler -> GlobalFilter -> CustomFilter -> LoggingFilter ->
Proxied Service - Response : Proxied Service -> LoggingFilter -> CustomFilter -> GlobalFilter -> Gateway Handler -> Gateway Client
- ## 위에서의 Request, Response는 현재 작성한 프로젝트 기준으로 작성한 내용입니다. ##
- 모든 필터는 AbstractGatewayFilterFactory를 상속 받아 apply method 구현
- Config라는 static class를 작성하여 args 매개변수를 전달 받아 사용할 수 있습니다.
[GlobalFilter]
- default-filters에 GlobalFilter을 기술하여 모든 인스턴스에 공통적으로 Filter를 적용
@Component
@Slf4j
public class GlobalFilter extends AbstractGatewayFilterFactory<GlobalFilter.Config> {
public GlobalFilter(){
super(Config.class);
}
@Data
public static class Config {
// Put the configuration properties
private String baseMessage;
private boolean preLogger;
private boolean postLogger;
}
@Override
public GatewayFilter apply(Config config){
// Global PRE filter
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response -> exchange.getResponse();
log.info("Global Filter baseMessage : {}", config.getBaseMessage());
if(config.isPreLogger()){
log.info("Global Filter Start Request id -> {}", request.getId());
}
// Global POST filter
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
if(config.isPostLogger()){
log.info("Global Filter End : response code -> {}", response.getStatusCodde());
}
}));
};
}
}
[CustomFilter]
- 각각의 route에 CustomFilter을 기술하여 별도의 Filter를 적용
@Component
@Slf4j
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config>{
public CustomFilter(){
super(Config.class);
}
public static class Config {
// Put the configuration properties
}
@Override
public GatewayFilter apply(Config config){
// Custom PRE filter
return (exchange, chain) -> {
// 기존의 HttpServletRequest가 아닌 비동기 방식인 ServerHttpRequest 사용
ServerHttpRequest request = exchange.request();
ServerHttpResponse response = exchange.response();
log.info("Custom PRE filter : request id -> {}", request.getId());
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("Custom POST filter : response code -> {}", response.getStatusCode());
}));
}
}
}
[LoggingFilter]
- 다른 Filter와 다르게 OrderedGatewayFilter를 사용함으로 Filter 호출의 순서를 변경
- Ordered.HIGHEST_PRECEDENCE -> 필터 순서를 제일 먼저 적용
- Ordered.LOWEST_PRECEDENCE -> 필터 순서를 제일 마지막에 적용
@Component
@Slf4j
public class LoggingFilter extends AbstractGatewayFilterFactory<LoggingFilter.Config> {
public LoggingFilter(){
super(Config.class);
}
@Data
public static class Config {
// Put the configuration properties
private String baseMessage;
private boolean preLogger;
private boolean postLogger;
}
@Override
public GatewayFilter apply(Config config){
GatewayFilter filter = new OrderedGatewayFilter((exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Logging Filter baseMessage : {}", config.getBaseMessage());
if(config.isPreLogger()){
log.info("Logging PRE Filter Start : request id -> {}", request.getId());
}
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
if(config.isPostLogger()){
log.info("Logging POST filter End : response code -> {}", response.getStatusCode());
}
}));
}, Ordered.HIGHEST_PRECEDENCE);
return filter;
}
}
[application.yml]
server:
port: 8000
eureka:
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: apigateway-service
cloud:
gateway:
default-filters:
- name: GlobalFilter
args:
baseMessage: Spring Cloud Gateway Global Filter
preLogger: true
postLogger: true
routes:
- id: first-service
uri: http://localhost:8001
predicates:
- Path=/first-service/**
filters:
- name: CustomFilter
- name: LoggingFilter
args:
baseMessage: Spring Cloud Gateway Logging Filter
preLogger: true
postLogger: true
[Global, Custom, Logging Filter 순서 확인]
- 앞서 언급한 LoggingFilter에서 Ordered.HIGHEST_PRECEDENCE이기 때문에 제일 먼저 실행됩니다.
- 다음에 GlobalFilter -> CustomFilter 순서로 호출됩니다.
- LoggingFilter -> GlobalFilter -> CustomFilter
그렇다면 LoggingFilter를 Ordered.LOWEST_PRECEDENCE로 변경하고 호출하게 된다면??
- GlobalFilter -> CustomFilter -> LoggingFilter 순서로 호출될 것입니다.
'Spring > Spring Cloud' 카테고리의 다른 글
Spring Cloud Gateway (0) | 2022.12.19 |
---|---|
Spring Cloud DiscoveryClient (0) | 2022.08.13 |
Spring Cloud Netflix Eureka (0) | 2022.08.07 |
댓글