๋ง์ดํฌ๋ก์๋น์ค ์๋จ์์ ๋ชจ๋ ์ธ๋ถ ์์ฒญ์ ๋จ์ผ ์ง์ ์ ์ญํ ์ ํ๋ API ๊ฒ์ดํธ์จ์ด. ํด๋ผ์ด์ธํธ๋ ๋ค์ ์๋น์ค๊ฐ ๋ช ๊ฐ ์๋ , ๊ฐ๊ฐ ์ด๋ ์ฃผ์์ ๋ ์๋ ์ ํ์ ์์ด ๊ฒ์ดํธ์จ์ด ํ ๊ณณ๋ง ํธ์ถํ๋ค.
๊ฐ์ ์๊ตฌ์ฌํญ์ WebFlux์ WebMVC ๋ ์คํ์ผ๋ก ๊ฐ๊ฐ ๊ตฌํํด ๋๋ํ ๋น๊ตํ๋ค.
โโโ service-discovery/ :8761 Eureka Server
โโโ gateway-common/ ๋ ๊ฒ์ดํธ์จ์ด๊ฐ ๊ณต์ ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
โโโ apigateway-webflux/ :8000 Netty ยท ๋
ผ๋ธ๋กํน
โโโ apigateway-webmvc/ :8010 Tomcat ยท ๋ธ๋กํน
โโโ alpha-service/ :8081 ๋ผ์ฐํ
๋์ (JWT ๋ฐ๊ธ ํฌํจ)
โโโ beta-service/ :8082 ๋ผ์ฐํ
๋์
Spring Boot 4.1.1 / Spring Cloud 2025.1.3 / Java 17.
๋ ๊ฒ์ดํธ์จ์ด๋ ๋์์ ๋์ธ ์ ์๋ค. ๊ฐ์ ์์ฒญ์ 8000๊ณผ 8010์ ๊ฐ๊ฐ ๋ณด๋ด ์๋ต๊ณผ ๋ก๊ทธ๋ฅผ ๋น๊ตํ๋ฉด ๋๋ค.
| ์ญํ | ์ค๋ช |
|---|---|
| ๋จ์ผ ์ง์ ์ | ํด๋ผ์ด์ธํธ๋ ๊ฒ์ดํธ์จ์ด ํฌํธ ํ๋๋ง ์๋ค. ์๋น์ค๊ฐ ๋์ด๋๋ ํธ์ถ ์ฃผ์๋ ๊ทธ๋๋ก๋ค. |
| ๋ผ์ฐํ | ์์ฒญ ๊ฒฝ๋ก(Path)๋ฅผ ๋ณด๊ณ ์ด๋ ์๋น์ค๋ก ๋ณด๋ผ์ง ํ๋ณํ๋ค. |
| ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ ์ฐ๋ | ๋์์ IPยทํฌํธ๊ฐ ์๋ lb://ALPHA-SERVICE ๋ผ๋ ์ด๋ฆ์ผ๋ก ์ง์ ํ๋ค. ์ค์ ์ฃผ์๋ Eureka๊ฐ ์๋ ค์ค๋ค. |
| ๋ก๋๋ฐธ๋ฐ์ฑ | ๊ฐ์ ์ด๋ฆ์ผ๋ก ์ฌ๋ฌ ์ธ์คํด์ค๊ฐ ๋ ์์ผ๋ฉด ์๋์ผ๋ก ๋ถ์ฐํ๋ค. |
| ํก๋จ ๊ด์ฌ์ฌ ์ฒ๋ฆฌ | ์ธ์ฆยท๋ก๊น ยทํค๋ ์กฐ์์ ๊ฒ์ดํธ์จ์ด๊ฐ ๋์ ์ฒ๋ฆฌํ๋ค. ๊ฐ ์๋น์ค๋ ์๊ธฐ ๋๋ฉ์ธ ๋ก์ง์๋ง ์ง์คํ๋ค. |
๋ง์ง๋ง ํญ๋ชฉ์ด ๊ฒ์ดํธ์จ์ด๋ฅผ ๋๋ ์ค์ง์ ์ธ ์ด์ ๋ค. JWT ๊ฒ์ฆ์ ์๋น์ค๋ง๋ค ๊ตฌํํ๋ฉด ์๋น์ค๊ฐ 10๊ฐ์ผ ๋ 10๋ฒ์ด ๋์ง๋ง, ๊ฒ์ดํธ์จ์ด์ ๋๋ฉด ํ ๊ณณ์์ ๋๋๋ค.
| ์์ฒญ ๊ฒฝ๋ก | ๋์ | ์ฒ๋ฆฌ |
|---|---|---|
/alpha-service/secure/** |
lb://ALPHA-SERVICE |
Cookie ํค๋ ์ ๊ฑฐ โ JWT ๊ฒ์ฆ |
/alpha-service/** |
lb://ALPHA-SERVICE |
์์ฒญ/์๋ต ํค๋ ์ถ๊ฐ โ ๋ผ์ฐํธ ๋ก๊น |
/beta-service/** |
lb://BETA-SERVICE |
์์ฒญ/์๋ต ํค๋ ์ถ๊ฐ โ ๋ผ์ฐํธ ๋ก๊น |
๋ผ์ฐํธ๋ ์์์๋ถํฐ ์์๋๋ก ๊ฒ์ฌํ๋ค. /alpha-service/secure/** ๊ฐ /alpha-service/** ๋ณด๋ค ์์ ์์ด์ผ
๋ณด์ ๊ฒฝ๋ก๊ฐ ์ธ์ฆ ์์ด ํต๊ณผํ์ง ์๋๋ค.
implementation 'org.springframework.cloud:spring-cloud-starter-gateway-server-webflux'Netty ์์์ ๋
ผ๋ธ๋กํน์ผ๋ก ๋์ํ๋ค. ์์ฒญ ์ฒ๋ฆฌ ์ ์ฒด๊ฐ Mono ์ฒด์ธ์ผ๋ก ์ด์ด์ง๋ฉฐ, ์ค๋ ๋๊ฐ I/O๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ์ ์ ๋์ง ์๋๋ค.
Spring Cloud Gateway์ ์์กฐ ๊ตฌํ์ด๊ณ ๊ธฐ๋ฅ ์ฑ์๋๊ฐ ๊ฐ์ฅ ๋๋ค. ํน๋ณํ ์ด์ ๊ฐ ์์ผ๋ฉด ์ด์ชฝ์ด ๊ธฐ๋ณธ ์ ํ์ด๋ค.
spring:
cloud:
gateway:
server:
webflux: # โ ์ ๋์ฌ์ ์ฃผ์. ํ๋ฆฌ๋ฉด ์๋ฌ ์์ด ๋ผ์ฐํธ๊ฐ 0๊ฐ๋ก ๋ฌ๋ค
routes:
- id: alpha-service-secure
uri: lb://ALPHA-SERVICE
predicates:
- Path=/alpha-service/secure/**
filters:
- RemoveRequestHeader=Cookie
- AuthorizationHeader| ํด๋์ค | ๋ฐฉ์ | ์ ์ฉ ๋ฒ์ |
|---|---|---|
GlobalLoggingFilter |
GlobalFilter ์ธํฐํ์ด์ค ๊ตฌํ |
๋น์ผ๋ก ๋ฑ๋ก๋ง ํ๋ฉด ์ ๋ผ์ฐํธ ์๋ ์ ์ฉ. yml ์ค์ ๋ถํ์ |
AuthorizationHeaderGatewayFilterFactory |
AbstractGatewayFilterFactory |
yml์์ AuthorizationHeader ๋ก ์ฐธ์กฐ |
RequestLoggingGatewayFilterFactory |
AbstractGatewayFilterFactory |
yml์์ RequestLogging ์ผ๋ก ์ฐธ์กฐ |
ํด๋์ค๋ช
์ด ...GatewayFilterFactory ๋ก ๋๋๋ฉด ํ๋ ์์ํฌ๊ฐ ์ ๋ฏธ์ฌ๋ฅผ ๋ผ๊ณ ์ด๋ฆ์ ์ธ์ํ๋ค.
shortcutFieldOrder() ๋ฅผ ์ ์ํ๋ฉด - RequestLogging=Alpha route ๊ฐ์ ์ถ์ฝ ํ๊ธฐ๋ ์ธ ์ ์๋ค.
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> chain.filter(exchange)
.then(Mono.fromRunnable(() -> log.info("POST: {}", ...)));
}ํต์ฌ ํ์
โ ServerWebExchange, Mono<Void>, GatewayFilterChain
implementation 'org.springframework.cloud:spring-cloud-starter-gateway-server-webmvc'์๋ธ๋ฆฟ(Tomcat) ์์์ ๋ธ๋กํน์ผ๋ก ๋์ํ๋ค. ์์ฒญ ํ๋๊ฐ ์ค๋ ๋ ํ๋๋ฅผ ์ ์ ํ ์ฑ ์๋ต๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค. ์คํํธ๋ ์ด์ค๊ฐ ๊ทธ๋๋ก ์ฝํ๊ณ ๋๋ฒ๊ฑฐ๊ฐ ์ ์ ๋์ํ๋ฉฐ, ํํฐ์์ ๋ธ๋กํน ๋ผ์ด๋ธ๋ฌ๋ฆฌ(JDBC ์กฐํ, ๋ธ๋กํน ์ธ์ฆ SDK ๋ฑ)๋ฅผ ๊ทธ๋ฅ ํธ์ถํด๋ ๋๋ค. Java 21+ ๊ฐ์ ์ค๋ ๋๋ฅผ ์ฐ๋ฉด ํ์ฅ์ฑ ์ํด๋ ์๋น ๋ถ๋ถ ํ๋ณต๋๋ค.
@Bean
public RouterFunction<ServerResponse> alphaServiceSecureRoute(JwtTokenValidator validator) {
return route("alpha-service-secure")
.route(path("/alpha-service/secure/**"), http())
.before(removeRequestHeader("Cookie"))
.filter(authorizationHeader(validator))
.filter(lb("ALPHA-SERVICE"))
.build();
}spring.cloud.gateway.server.webmvc.routes ๋ก yml์ ์ธ ์๋ ์๋ค. ๋ค๋ง ์ปค์คํ
ํํฐ๋ฅผ yml์์ ์ด๋ฆ์ผ๋ก ์ฐธ์กฐํ๋ ค๋ฉด
FilterSupplier ๋น์ ๋ฐ๋ก ๋ฑ๋กํด์ผ ํ๊ณ , ๊ทธ ํํฐ๋ ์ ์ ๋ฉ์๋์ฌ์ผ ํด์ ์์กด์ฑ์ MvcUtils.getApplicationContext()
๋ก ๊บผ๋ด ์จ์ผ ํ๋ค. DSL์ ์ฐ๋ฉด ํํฐ๋ฅผ ๊ทธ๋ฅ ๋น์ผ๋ก ์ฃผ์
๋ฐ์ ์ ์์ด ์ฌ๊ธฐ์๋ DSL์ ํํ๋ค.
RouterFunction ์ ๋น ๋ฑ๋ก ์์๋๋ก ํ๊ฐ๋๋ฏ๋ก ๋ ๊ตฌ์ฒด์ ์ธ ๊ฒฝ๋ก๋ฅผ ๋จผ์ ์ ์ธํ๋ค.
| ํด๋์ค | ๋ฐฉ์ | ์ ์ฉ ๋ฒ์ |
|---|---|---|
GlobalLoggingFilter |
OncePerRequestFilter (์๋ธ๋ฆฟ ํํฐ) |
๋ชจ๋ ์์ฒญ. actuator ๋ฑ ๊ฒ์ดํธ์จ์ด ๋ผ์ฐํธ๊ฐ ์๋ ๊ฒ๋ ํฌํจ |
AuthorizationHeaderFilters.authorizationHeader() |
HandlerFilterFunction |
DSL์์ .filter(...) ๋ก ๋ถ์ฐฉ |
RequestLoggingFilters.requestLogging() |
HandlerFilterFunction |
DSL์์ .filter(...) ๋ก ๋ถ์ฐฉ |
Gateway MVC์๋ GlobalFilter ํ์ฅ์ ๋ default-filters ์ค์ ๋ ์๋ค. ์๋ธ๋ฆฟ ์คํ์ด๋ฏ๋ก ํ์ค ์๋ธ๋ฆฟ ํํฐ๊ฐ
๊ทธ ์๋ฆฌ๋ฅผ ๋์ ํ๋ค. ์ ์ฉ ๋ฒ์๊ฐ ๋ผ์ฐํธ ๋จ์๊ฐ ์๋๋ผ ์ ์์ฒญ์ด๋ผ๋ ์ฐจ์ด๊ฐ ์๋ค.
public static HandlerFilterFunction<ServerResponse, ServerResponse> requestLogging(String baseMessage) {
return (request, next) -> {
log.info("PRE: {} {}", request.method(), request.path());
ServerResponse response = next.handle(request); // ๋ธ๋กํน
log.info("POST: {}", response.statusCode());
return response;
};
}ํต์ฌ ํ์
โ ServerRequest, ServerResponse, HandlerFilterFunction, RouterFunction
WebFlux :8000 |
WebMVC :8010 |
|
|---|---|---|
| ์คํํฐ | ...-gateway-server-webflux |
...-gateway-server-webmvc |
| ๋ฐํ์ | Netty, ๋ ผ๋ธ๋กํน | Tomcat, ๋ธ๋กํน |
| ์ค์ ์ ๋์ฌ | spring.cloud.gateway.server.**webflux**.* |
spring.cloud.gateway.server.**webmvc**.* |
| ํจํค์ง | o.s.c.gateway.* |
o.s.c.gateway.**server.mvc**.* |
| ๋ผ์ฐํธ ์ ์ | application.yml | Java DSL (yml๋ ๊ฐ๋ฅ) |
| ์ ์ญ ํํฐ | GlobalFilter ๊ตฌํ |
์๋ธ๋ฆฟ Filter |
| ๋ผ์ฐํธ ํํฐ | AbstractGatewayFilterFactory |
HandlerFilterFunction |
| ์ปค์คํ ํํฐ๋ฅผ yml์์ ์ฐธ์กฐ | ๋น ๋ฑ๋ก๋ง ํ๋ฉด ๋จ | FilterSupplier ๋น ์ถ๊ฐ ๋ฑ๋ก ํ์ |
๋์ ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ์ด ๋ฃ์ ์๋ ์๋ค. ํ๋๋ ๋ฆฌ์กํฐ๋ธ, ํ๋๋ ์๋ธ๋ฆฟ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ๋จ๊ธฐ ๋๋ฌธ์ ํด๋์คํจ์ค์ ํจ๊ป ๋๋ฉด ์ถฉ๋ํ๋ค. ๊ทธ๋์ ๋ชจ๋์ ๋๋ด๋ค.
| ํด๋์ค | ์ญํ |
|---|---|
JwtTokenValidator |
ํ ํฐ ์๋ช ยทsubject ๊ฒ์ฆ. ์น ํ์ ์ ์ ํ ์ฐ์ง ์๋๋ค |
JwtProperties |
jwt.secret ๋ฐ์ธ๋ฉ + ๊ฒ์ฆ |
GatewayLoggingProperties |
์ ์ญ ๋ก๊น ํํฐ ์ค์ |
JWT ๊ฒ์ฆ์ ํํฐ์์ ๋ถ๋ฆฌํด๋ ๋๋ถ์, ์น ์คํ์ ํต์งธ๋ก ๊ฐ์์์ด๋ ์ด ์ฝ๋์ ํ ์คํธ 5๊ฐ๋ ๊ทธ๋๋ก ์ฌ์ฌ์ฉ๋๋ค. ์คํ ์ฐจ์ด๊ฐ ํํฐ 3๊ฐ์ ๋ผ์ฐํธ ์ ์์๋ง ๊ฐํ๋ ๊ตฌ์กฐ๋ค.
service-discovery ๋ฅผ ๋จผ์ ๋์ด๋ค. ๋๋จธ์ง๋ ์์ ๋ฌด๊ด.
./gradlew :service-discovery:bootRun
./gradlew :alpha-service:bootRun
./gradlew :beta-service:bootRun
./gradlew :apigateway-webflux:bootRun
./gradlew :apigateway-webmvc:bootRun๊ฒ์ดํธ์จ์ด๊ฐ Eureka ๋ ์ง์คํธ๋ฆฌ๋ฅผ ๋ฐ์์ค๊ธฐ๊น์ง ์ต๋ 30์ด๊ฐ ๊ฑธ๋ฆฐ๋ค.
๊ทธ ์ ๊น์ง ๋์ค๋ No servers available for service: ALPHA-SERVICE ๊ฒฝ๊ณ ๋ ์ ์์ด๋ค.
Eureka ๋์๋ณด๋: http://localhost:8761
๊ฐ์ ์์ฒญ์ ๋ ํฌํธ์ ๋ณด๋ด ๋น๊ตํ๋ค.
curl http://localhost:8000/alpha-service/welcome # WebFlux
curl http://localhost:8010/alpha-service/welcome # WebMVC
curl http://localhost:8000/alpha-service/check # ์ฒ๋ฆฌํ ์ธ์คํด์ค์ ์ค์ ํฌํธ๊ฐ ์ฐํ๋ค
curl http://localhost:8010/beta-service/welcome์ธ์ฆ์ด ๊ฑธ๋ฆฐ ๊ฒฝ๋ก:
# ํ ํฐ ์์ด ํธ์ถํ๋ฉด 401
curl -i http://localhost:8000/alpha-service/secure/hello
# ํ ํฐ ๋ฐ๊ธ ํ ์ฌํธ์ถ
TOKEN=$(curl -s -X POST http://localhost:8000/alpha-service/token \
| python3 -c 'import sys,json;print(json.load(sys.stdin)["accessToken"])')
curl -H "Authorization: Bearer $TOKEN" http://localhost:8000/alpha-service/secure/hello
curl -H "Authorization: Bearer $TOKEN" http://localhost:8010/alpha-service/secure/helloํ ํฐ ๋ฐ๊ธ์ ์๋ ์ธ์ฆ ์ ์ฉ ์๋น์ค์ ์ฑ ์์ด๋ค. ์ฌ๊ธฐ์๋ ๊ฒ์ดํธ์จ์ด ํํฐ๋ฅผ ํ์ธํ๊ธฐ ์ํด
alpha-service์ ์ต์ ๊ตฌํ์ผ๋ก ๋์๋ค.
beta-service/src/main/resources/application.yml ์ port ๋ฅผ 0 ์ผ๋ก ๋ฐ๊พธ๊ณ ์ฌ๋ฌ ์ธ์คํด์ค๋ฅผ ๋์ด ๋ค
/beta-service/check ๋ฅผ ๋ฐ๋ณต ํธ์ถํ๋ฉด, ๊ฒ์ดํธ์จ์ด ์ค์ ์ ๊ทธ๋๋ก์ธ ์ฑ๋ก ์๋ต ํฌํธ๊ฐ ๋ฒ๊ฐ์ ๋ฐ๋๋ค.
alpha-service ์ beta-service ๋ 8081, 8082 ๋ก ์ง์ ํธ์ถํด๋ ์๋ตํ๋ค.
๊ฒ์ดํธ์จ์ด๋ ๋ฆฌ๋ฒ์ค ํ๋ก์์ผ ๋ฟ ํธ๋ํฝ์ ๊ฐ๋ก์ฑ์ง ์๋๋ค.
๋ก์ปฌ์์๋ ์ฅ์ ์ง์ ์ ๊ฐ๋ฆฌ๋ ๋ฐ ์คํ๋ ค ํธํ๋ค โ 8000์ด ์คํจํ ๋ 8081์ ์ง์ ๋๋ ค ๋ณด๋ฉด ์๋น์ค๊ฐ ์ฃฝ์ ๊ฒ์ธ์ง ๋ผ์ฐํ ์ด ํ๋ฆฐ ๊ฒ์ธ์ง ๋ฐ๋ก ์ ์ ์๋ค. ์ด์ ํ๊ฒฝ์ด๋ผ๋ฉด ๊ฒ์ดํธ์จ์ด๋ง ์ธ๋ถ์ ๋ ธ์ถํ๊ณ ๋๋จธ์ง๋ ๋ด๋ถ๋ง์ ๋๊ฑฐ๋, ์๋น์ค๋ฅผ ๋ฃจํ๋ฐฑ์๋ง ๋ฐ์ธ๋ฉํ๋ค.
server:
address: 127.0.0.1| ํค | ์์น | ๋น๊ณ |
|---|---|---|
jwt.secret |
๋ ๊ฒ์ดํธ์จ์ด, alpha-service |
๊ฐ์ด ๋ชจ๋ ๊ฐ์์ผ ํ๋ค. HS256์ 256bit ์ด์์ ์๊ตฌํ๋ฏ๋ก 32์ ์ด์. ์งง์ผ๋ฉด ๊ธฐ๋ ์์ ์ ์คํจํ๋ค. |
jwt.expiration |
alpha-service |
ํ ํฐ ์ ํจ ๊ธฐ๊ฐ. 24h, 30m ํ์ |
gateway.logging.* |
๋ ๊ฒ์ดํธ์จ์ด | ์ ์ญ ๋ก๊น ํํฐ์ ๋ฌธ๊ตฌ์ on/off. ์๋ตํ๋ฉด ๊ธฐ๋ณธ๊ฐ |
Config Server ๋ฅผ ๋ถ์ด๋ ค๋ฉด spring.config.import: optional:configserver:http://127.0.0.1:8888/ ๋ฅผ ์ด๋ค.

