Spring Cloud Gateway: 기본 예제
Source: Dev.to

Spring Cloud Gateway(게이트웨이 또는 Edge Service라고도 함)는 동적 라우팅 서버입니다. 즉, 마이크로서비스에 대한 중앙 집중식 접근 지점을 제공할 수 있습니다. 또한 필터나 프레디케이트 등을 추가하여 기능을 확장할 수 있습니다.
1. Spring Cloud Gateway 구성
Spring Initializr(또는 선호하는 IDE)를 사용하여 프로젝트를 생성하고 다음 의존성을 선택하십시오:
- Eureka Discovery Client
- Gateway
프로젝트는 Eureka Server에도 등록되므로 다음 구성을 추가하십시오:
@EnableEurekaClient
@SpringBootApplication
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
}
Application properties (YAML)
spring:
application:
name: gateway-server-service
server:
port: 8090
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
2. Routes
Edge/Gateway에 대한 최소 필수 구성은 routes 입니다. 이 라우트들은 게이트웨이에서 요청을 받아 응답을 제공할 서비스로 리다이렉트합니다.
기본 라우트 구성 (YAML)
spring:
cloud:
gateway:
routes:
- id: employees
uri: lb://employees
predicates:
- Path=/api/employees/**
filters:
- StripPrefix=2
설명
| Element | Description |
|---|---|
id | 라우트의 고유 식별자입니다. |
uri | 게이트웨이가 리다이렉트할 서비스를 찾을 주소입니다. Eureka와 같은 서비스 디스커버리를 사용할 경우 lb(Load Balancer)로 시작해야 합니다. |
predicates | 리다이렉션이 성립하기 위해 만족해야 하는 규칙들입니다. |
filters | 선언된 라우트를 통과하는 요청/응답을 조작하는 작업들입니다. |
위 예시에서는 게이트웨이가 employees 라는 마이크로서비스로 라우팅합니다. 해당 마이크로서비스의 포트에 직접 접근하는 대신, 게이트웨이 포트(8090)에서 Spring Cloud Gateway를 호출하면 응답을 받을 수 있습니다.
2.1 Predicates
Predicates는 리다이렉션이 성공하기 위해 만족해야 하는 규칙들의 목록입니다. 경로, 헤더, HTTP 메서드, 쿼리 파라미터, 쿠키 등을 기반으로 할 수 있습니다.
예시
predicates:
- Path=/api/products/**
- Header=token, \d+
- Method=GET, POST
- Query=color
- Cookie=color, blue
의미
| Predicate | Description |
|---|---|
Path | 선언된 경로와 일치하는 요청을 리다이렉트합니다. |
Header | 지정된 헤더가 존재하고, 값이 주어진 정규식과 일치하는지 확인합니다. |
Method | 나열된 HTTP 메서드만 허용합니다. |
Query | URL에 해당 쿼리 파라미터가 존재해야 합니다. |
Cookie | 지정된 쿠키가 존재하는지(그리고 선택적으로 값이 일치하는지) 확인합니다. |
2.2 Spring Cloud Gateway Factory Filters
Factory filters는 요청 및 응답을 조작할 수 있게 해줍니다(예: 헤더 추가, 요청 파라미터 추가).
구성 (YAML)
filters:
- AddRequestHeader=token-request, 123456
- AddResponseHeader=token-response, 12345678
- SetResponseHeader=Content-Type, text/plain
- AddRequestParameter=name, andres
이 필터들은 선언된 라우트에만 적용됩니다.
2.3 Spring Cloud Gateway Global Filters
Global filters는 라우트별로 선언할 필요 없이 모든 요청에 적용됩니다.
구현 예시
package com.funcionaenmimaquina.springboot.app.gateway.filters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class ExampleGlobalFilter implements GlobalFilter, Ordered {
private final Logger logger = LoggerFactory.getLogger(ExampleGlobalFilter.class);
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
logger.info("Executing request filter");
// Modifying the request
exchange.getRequest()
.mutate()
.header("environment", "dev")
.build();
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
logger.info("Executing response filter");
// Adding a cookie to the response
exchange.getResponse()
.addCookie(ResponseCookie.from("myCookie", "myValue")
.path("/")
.maxAge(3600)
.build());
}));
}
@Override
public int getOrder() {
// Lower values have higher precedence
return -1;
}
}
이 예제에서 필터는 모든 들어오는 요청에 environment 헤더를 추가하고, 모든 응답에 myCookie이라는 쿠키를 추가합니다.
Global Filter Example (continued)
o("Executing response filter");
// Modifying the response
Optional.ofNullable(exchange.getRequest().getHeaders().getFirst("environment"))
.ifPresent(value -> {
exchange.getResponse().getHeaders().add("env", value);
});
exchange.getResponse().getHeaders().setContentType(MediaType.TEXT_PLAIN);
}))
;
@Override
public int getOrder() {
return 1;
}
}
예제 작동 방식
- **
GlobalFilter**와Ordered인터페이스를 구현합니다. getOrder는 여러 글로벌 필터가 존재할 때 실행 순서를 정의합니다.filter메서드에 요청과 응답을 다루는 모든 로직이 들어갑니다.- 24 줄에서는 요청을 조작할 수 있는 위치(예: 헤더 추가)를 보여줍니다.
- 27 줄에서는
.then(Mono.fromRunnable(...))을 사용해 응답을 조작하는 방법을 보여줍니다. - 31 줄은 특정 요청 헤더가 존재할 경우 응답에 헤더를 추가합니다.
- 34 줄은 응답의 미디어 타입을 평문(
text/plain)으로 강제합니다.
2.4 Filter Factory (Custom Gateway Filter)
특정 라우트에만 필터를 적용하고 싶다면, 커스텀 필터 팩토리를 생성합니다:
@Component
public class ExampleGatewayFilterFactory
extends AbstractGatewayFilterFactory {
private final Logger logger = LoggerFactory.getLogger(ExampleGatewayFilterFactory.class);
public ExampleGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
logger.info("Zone to modify the request");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
logger.info("Zone to modify the response");
Optional.ofNullable(config.cookieValue).ifPresent(cookieVal -> {
exchange.getResponse()
.addCookie(ResponseCookie.from(config.cookieName, cookieVal).build());
});
}));
};
}
@Override
public String name() {
return "ExampleCookie";
}
@Override
public List shortcutFieldOrder() {
return Arrays.asList("cookieName", "cookieValue");
}
public static class Config {
private String cookieName;
private String cookieValue;
// Getters and Setters
public String getCookieValue() { return cookieValue; }
public void setCookieValue(String cookieValue) { this.cookieValue = cookieValue; }
public String getCookieName() { return cookieName; }
public void setCookieName(String cookieName) { this.cookieName = cookieName; }
}
}
application.yml에서 사용 예시
filters:
- StripPrefix=2
- ExampleCookie=user, myName
코드가 수행하는 작업
- YAML 파일에 정의된 값을 사용해 응답에 쿠키를 추가합니다.
관례 및 요구 사항
- 클래스 이름은
FilterFactory로 끝나야 합니다. AbstractGatewayFilterFactory를 상속합니다.- 내부
Config클래스는 YAML 파일에서 전달된 값을 저장합니다. - 필터 로직은
apply메서드에 위치합니다. name()메서드가 반환하는 값은 YAML에서 사용되는 키와 일치해야 합니다(또는 기본적으로 클래스명 접두어와 일치).shortcutFieldOrder는 짧은 표기법 값이 설정 필드에 매핑되는 순서를 정의합니다.
application.yml에서 이 필터를 참조한 라우트에만 적용됩니다.
결론
이제 다음을 이해했습니다:
- Spring Cloud Gateway가 무엇이며 어떤 문제를 해결하는지.
- 기능을 확장하기 위해 predicates와 filters를 구성하는 방법.
- 세밀한 제어를 위해 global filters와 custom filter factories를 만드는 방법.
실제 프로젝트에서 게이트웨이를 구축하고 맞춤화하여 편하게 사용할 수 있도록 연습하세요.
