package com.example.apigatewayservice.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
@Component
@Slf4j
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config> {
public CustomFilter(){
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
// Custom Pre Filter
return ((exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Custom Pre Filter: request id -> {}", request.getId());
// Custom Post Filter
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("Custom Post Filter: response id -> {}", response.getStatusCode());
}));
});
}
public static class Config{
// Put the configuration properties
}
server:
port: 8000
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: api-gateway-service
cloud:
gateway:
routes:
- id: first-service
uri: http://localhost:8081/
predicates:
- Path=/first-service/**
filters:
# - AddRequestHeader=first-request, first-request-header2
# - AddResponseHeader=first-response, first-response-header2
- CustomFilter
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
# - AddRequestHeader=second-request, second-request-header2
# - AddResponseHeader=second-response, second-response-header2
- CustomFilter
이번엔 커스텀 필터를 만들어 적용함.
전에 했던건 주석 처리하고 커스텀 필터 파일 작성.
AbstractGatewayFilterFactory 상속 받고 데이터 타입을 커스텀 필터.config로 함.
생성자 만들어주고
apply 오버라이딩
exchange, chain 매개변수 받고 반환
exchange에서 request, response 얻어옴
custom pre filter에 간단 작성
custom post filter를 작성
chain에다 연결시켜 exchange넣고 비동식 단일로 mono사용
server:
port: 8000
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: api-gateway-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:8081/
predicates:
- Path=/first-service/**
filters:
# - AddRequestHeader=first-request, first-request-header2
# - AddResponseHeader=first-response, first-response-header2
- CustomFilter
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
# - AddRequestHeader=second-request, second-request-header2
# - AddResponseHeader=second-response, second-response-header2
- CustomFilter
package com.example.apigatewayservice.filter;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
@Component
@Slf4j
public class GlobalFilter extends AbstractGatewayFilterFactory<GlobalFilter.Config> {
public GlobalFilter(){
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
// Custom 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());
}
// Custom Post Filter
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
if(config.isPostLogger()){
log.info("Global Filter End: response code -> {}", response.getStatusCode());
}
}));
});
}
@Data
public static class Config{
private String baseMessage;
private boolean preLogger;
private boolean postLogger;
}
}
커스텀 필터와 마찬가지로 Global filter 파일 작성
default filter는 처음 시작해서 마지막으로 끝난다.
yml 파일에 args로 config 클래스 변수에 넣어준다.
@Data 사용함.
server:
port: 8000
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: api-gateway-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:8081/
predicates:
- Path=/first-service/**
filters:
# - AddRequestHeader=first-request, first-request-header2
# - AddResponseHeader=first-response, first-response-header2
- CustomFilter
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
# - AddRequestHeader=second-request, second-request-header2
# - AddResponseHeader=second-response, second-response-header2
- name: CustomFilter
- name: LoggingFilter
args:
baseMessage: Hi, There
preLogger: true
postLogger: true
second service에만 로깅 필터를 따로 달아줌.
필터가 하나면 -하고 바로 필터 이름을 쓰고, 여러 개이면 name: 을 작성하고 써야한다.
return 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: request id -> {}", request.getId());
}
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
if(config.isPostLogger()){
log.info("Logging Post Filter: response code -> {}", response.getStatusCode());
}
}));
}, Ordered.HIGHEST_PRECEDENCE);
로깅 필터 코드이다. 리턴 부분만 OrderedGatewayFilter로 작성했다. 그리고 두번째 파라미터로 순서를 매기는데 HIGHEST로 하여 필터 중 가장 먼저 필터로 나오게 하였다.
순서로 보면 로깅 -> 글로벌 -> 커스텀 순서이다.