
FIlter
Spring Cloud Gateway에서 Filter는 요청(Request) 및 응답(Response)을 처리하거나 변환하는 데 사용된다.
필터를 설정 이유
- 공통 로직 처리:
- 모든 요청에 대해 동일한 작업(예: 인증, 로깅)을 중앙에서 처리가 가능하다.
- 유연한 요청 처리:
- 서비스별로 맞춤형 필터를 적용해 요청을 동적으로 변환이 가능하다.
- 관리와 확장성:
- 개별 서비스에 중복 코드를 작성할 필요 없이 Gateway에서 일괄 관리 가능하다.
.yml 필터 작성
server:
port: 8000
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: api-gateway-service
cloud:
gateway:
default-filters: # 모든 요청에 공통적으로 적용
- name: AddRequestHeader
args:
name: Global-Header
value: Global-Header-Value
- name: AddResponseHeader
args:
name: Global-Response
value: Global-Response-Value
routes:
# 사용자 서비스 그룹
- id: user-service
uri: lb://USER-SERVICE
predicates:
- Path=/user-service/**
filters:
- AddRequestHeader=User-Request, User-Request-Header
- AddResponseHeader=User-Response, User-Response-Header
# 주문 서비스 그룹
- id: order-service
uri: lb://ORDER-SERVICE
predicates:
- Path=/order-service/**
filters:
- name: RewritePath
args:
regexp: "/order-service/(?<segment>.*)"
replacement: "/${segment}"
- name: Hystrix
args:
name: orderFallback
fallbackUri: forward:/fallback/order-service
# 결제 서비스 그룹
- id: payment-service
uri: lb://PAYMENT-SERVICE
predicates:
- Path=/payment-service/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
코드 레벨 필터 구현
@Configuration
public class FilterConfig {
@Bean
public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
return builder.routes()
// 사용자 서비스
.route("user-service", r -> r.path("/user-service/**")
.filters(f -> f.addRequestHeader("User-Request", "User-Request-Header")
.addResponseHeader("User-Response", "User-Response-Header"))
.uri("lb://USER-SERVICE"))
// 주문 서비스
.route("order-service", r -> r.path("/order-service/**")
.filters(f -> f.rewritePath("/order-service/(?<segment>.*)", "/${segment}")
.hystrix(config -> config.setName("orderFallback")
.setFallbackUri("forward:/fallback/order-service")))
.uri("lb://ORDER-SERVICE"))
// 결제 서비스
.route("payment-service", r -> r.path("/payment-service/**")
.filters(f -> f.requestRateLimiter(config -> config.setRateLimiter(redisRateLimiter())))
.uri("lb://PAYMENT-SERVICE"))
.build();
}
// Redis 기반 Rate Limiter Bean 등록
private RedisRateLimiter redisRateLimiter() {
return new RedisRateLimiter(10, 20);
}
}
Custom Filter 구현
@Component
@Slf4j
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config> {
public CustomFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return ((exchange, chain) -> {
// Pre Filter
ServerHttpRequest request = exchange.getRequest();
long startTime = System.currentTimeMillis();
log.info("Custom Pre Filter: Request ID -> {}", request.getId());
log.info("Custom Pre Filter: URI -> {}", request.getURI());
// Add a custom request header
ServerHttpRequest modifiedRequest = request.mutate()
.header("Custom-Request-Header", "CustomRequestValue")
.build();
// Post Filter
return chain.filter(exchange.mutate().request(modifiedRequest).build())
.then(Mono.fromRunnable(() -> {
ServerHttpResponse response = exchange.getResponse();
long processingTime = System.currentTimeMillis() - startTime;
log.info("Custom Post Filter: Response Status Code -> {}", response.getStatusCode());
log.info("Custom Post Filter: Processing Time -> {}ms", processingTime);
// Add a custom response header
response.getHeaders().add("Custom-Response-Header", "CustomResponseValue");
}));
});
}
public static class Config {}
}
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:
- CustomFilter
# 두 번째 서비스
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
- CustomFilter
default-filters:
- name: AddRequestHeader
args:
name: Global-Request
value: GlobalRequestValue
- name: AddResponseHeader
args:
name: Global-Response
value: GlobalResponseValue
'Infra' 카테고리의 다른 글
| MSA (1) - Spring Cloud Netflix Eureka (0) | 2025.01.02 |
|---|